Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular unable to instantiate module when loaded using RequireJS

There is something really weird going on when I'm using RequireJS with AngularJS. I managed to load all my angular dependencies through RequireJS. I can see those scripts downloaded when I open up the Sources pane in Chrome's developer tool. But Angular keeps throwing an error in the console that it failed to instantiate the module:

Uncaught Error: [$injector:modulerr] Failed to instantiate module MyTestApp due to:
Error: [$injector:nomod] Module 'MyTestApp' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure...<omitted>...0)

It seems like Angular, when loaded with RequireJS, cannot bind with the ng-app tag in the HTML page. I'm not sure if this is the case but it seems like so to me because when I import angular.min.js manually into the HTML page, it all works fine.

Did I do anything wrong when using RequireJS with Angular? How should I use the two together? Here's how my code look:

index.html

<!doctype html>
<html lang="en" ng-app="MyTestApp">
<head>
  <meta charset="utf-8">
  <title>AngularJS</title>
  <link rel="stylesheet" href="css/style.css"/>
  <script data-main="main" src="js/require.js"></script>
</head>
<body>
  <div ng-controller="TestController">{{helloMessage}}</div>
</body>
</html>

main.js

require.config({
    baseUrl: "scripts/app",

    shim: {
        "angular": {
            exports: "angular"
        },
        "angular.route": {
            deps: ["angular"]
        },
        "bootstrapper": {
            deps: ["angular", "angular.route"]   
        },

    },

    paths: {
        "angular": "../angular",
        "angular.route": "../angular-route",
        "bootstrapper": "bootstrapper"
    }
});

require(["angular", "angular.route", "bootstrapper"],
    (angular, ngRoute, bootstrapper) => {
        bootstrapper.start();
    }
);

bootstrapper.js

function run() {
       app = angular.module("MyTestApp", ["ngRoute"]);
       app.controller("TestController", TestController);
       console.log(app); //Prints object to console correctly, ie, angular was loaded.
}
like image 311
Carven Avatar asked Apr 14 '14 12:04

Carven


2 Answers

Here is how I would do it (DEMO).

In main.js, require angular, your app and maybe a controllers.js and other files:

require(['angular', 'app'], function (app) {
    angular.element(document).ready(function () {
        angular.bootstrap(document, ['MyTestApp']);
    });
});

In app.js, require angular and angular route:

define(['angular', 'angular.route'], function() {
    var app = angular.module("MyTestApp", ["ngRoute"]);

    return app;
});

This is manual bootstraping and therefore does not need the ng-app tag at all.

I'm currently working on a pretty big application with angular and requirejs and I prefer to load the "big" libraries that are used by the whole app anyway independently from requirejs. So I load one big file which includes angular, angular-route, requirejs, main.js in the beginning. Or if it makes sense to use a CDN version, load it from there. On the other hand I load every controller, directive, filter and service on request. I currently have 50+ controllers which allready makes a difference in initial load time.

But that all depends on the size of your app.

like image 159
Marcel Gwerder Avatar answered Sep 27 '22 20:09

Marcel Gwerder


First you does not need to get a variable from the load of "angular.route". The module will be directly loaded in angular.

I think you should also wait for the dom ready event and also make a requirejs app module that will be in charge of loading all app dependencies:

app/app.js:

define([
  "angular",
  "angular-route",
  "app/controllers",
  "app/directives",
  [...]
], function(angular){
  var app = angular.module('app', [
    "ngRoute",
    "app.controllers",
    "app.directives",
    [...]
    ])
    .config([function(){
      // app configuration goes here
    }]);

    return app;
})

main.js

require(["angular", "app/app"],
  function (angular, app){
    angular.element(document).ready(function() {
      angular.bootstrap(document, [app.name]);
    });
  }
);
like image 44
Charles Avatar answered Sep 27 '22 22:09

Charles