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>

3 Answers 3

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.

Sign up to request clarification or add additional context in comments.

4 Comments

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/
Note that according the official documentation 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.
@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.
But why would you use domReady when you could use jQuery .ready() to bootstrap when the DOM is loaded?
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'}
      }
});

3 Comments

Did not change anything, unfortunately.
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.
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.
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']);
        })
    })
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.