2

I'm trying to have angular and jquery loaded with requirejs. The best I can do is that 50% of the time everything loads correctly, the other half I get the error No Module: mainApp

I'm assuming this is breaking half the time based on the speed on which requirejs is asynchronously loading the scripts.

When it works, I see the "Hello World" test (although I do see {{text}} flash before it is replaced, but I've been reading how to fix that here). The rest of the time I get the error and {{text}} just stays on the screen.

Github Repo

Tree:

index.html
- js
    - libs
        require.js
    - modules
        mainApp.js
    main.js

main.js

require.config({
  paths: {
    'jQuery': '//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min',
    'angular': '//ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular',
  },
  shim: {
    'angular' : {'exports' : 'angular'},
    'jQuery': {'exports' : 'jQuery'}
  }
});

require(['jQuery', 'angular', 'modules/mainApp'] , function ($, angular, mainApp) {
  $(function () { // using jQuery because it will run this even if DOM load already      happened
    angular.bootstrap(document, ['mainApp']);
  });
});

modules/mainApp.js

define(['angular'], function (angular) {
  return angular.module('mainApp' , []).controller('MainCtrl', ['$scope', function ($scope) {
      $scope.text = 'Hello World';
  }]);
});

Relevant index.html

<head>
    <script src="js/libs/require.js" data-main="js/main"></script>
</head>
<body>
    <div ng-app="mainApp">
        <div ng-controller="MainCtrl">
            {{text}}
        </div>
    </div>
</body>
Nick Brown
  • 1,167
  • 1
  • 21
  • 38

3 Answers3

6

You can use domReady (UPDATED) to make sure that the DOM is fully loaded, i.e. all JS files are there, before bootstrapping your application.

requirejs.config({
    paths: {
        jquery: '/path/to/jquery',
        angular: 'path/to/angular',
        domReady: '/path/tp/domReady'
    }, shim: {
        angular: {
            exports: 'angular'
        },  
    }   
});
define(['jquery', 'angular', 'modules/mainApp'], 
    function($, angular, 'mainApp') {
        // tell angular to wait until the DOM is ready
        // before bootstrapping the application
        require(['domReady'], function() {
            angular.bootstrap(document, ['mainApp']);
        }); 
});

See the RequireJS official documentation for more information on this gotcha:

It is possible when using RequireJS to load scripts quickly enough that they complete before the DOM is ready. Any work that tries to interact with the DOM should wait for the DOM to be ready.

The trick is found on this blog post.

EDIT If you follow the blog post's advice, please use this domReady script instead of the one I previously posted: https://github.com/requirejs/domReady/blob/master/domReady.js.

Lim H.
  • 9,870
  • 9
  • 48
  • 74
  • Didn't seem to make any difference. I even tried to match the blog post's example syntax as exactly as possible. Here's the project with your recommended changes: `https://github.com/nick-brown/broken-require/tree/domReady/` – Nick Brown Nov 12 '13 at 21:17
  • Note that according [the official documentation](http://requirejs.org/docs/api.html#pageload) you don't use `domready` like this; you either wrap code in `domready()` call or require it using plugin syntax, i.e. `'domReady!'`. No idea if this is enough to fix OP's problem, though. – kryger Nov 12 '13 at 22:34
  • 1
    @Nick Brown The blog post uses a different domReady script, hence the differences in syntax. I wrote that post but forgot which script was used. Don't use the one that the official documentation suggested. I've submitted a pull request for your review. – Lim H. Nov 13 '13 at 08:05
  • But why would you use domReady when you could use jQuery .ready() to bootstrap when the DOM is loaded? – Dustin Blake Apr 08 '14 at 14:18
2

Add Jquery as a dependency for Angular in the shim.

require.config({
      paths: {
        'jQuery': '//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min',
        'angular': '//ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular',
      },
      shim: {
        'angular' : {'exports' : 'angular', deps: ['jQuery']},
        'jQuery': {'exports' : 'jQuery'}
      }
});
Rob
  • 2,721
  • 1
  • 20
  • 27
  • Did not change anything, unfortunately. – Nick Brown Nov 12 '13 at 20:52
  • Seems to work when you add https:// to your CDN's You will still need to bootstrap your app. angular.bootstrap(document, ["app"]); But this should get you passed the loading issue. – Rob Nov 12 '13 at 21:34
  • Strange, still doesn't work for me but I'm going to give it a try when I get home and on a different connection. – Nick Brown Nov 12 '13 at 22:34
1

This might be a late response but as Dustin Blake said, you can also use jQuery .ready() instead of including another module like domReady.

requirejs.config({
    paths: {
        jquery: '/path/to/jquery',
        angular: 'path/to/angular'
    }, shim: {
        angular: {
            exports: 'angular'
        },  
    }   
});

require(['jquery'], function($) {
    $(document).ready(function(){
        // I like it this way instead of including 
        // everything in the parent function so it's easier to read
        require(['angular', "modules/mainApp"], function(){
         angular.bootstrap(document, ['mainApp']);
        })
    })
});
ginad
  • 1,863
  • 2
  • 27
  • 42