doque
doque

Reputation: 2733

RequireJS is loading angular app, but doesn't create app.controller

I've set up a very basic environment for loading AngularJS components (which are managed by Bower) using RequireJS. My index.html is very basic:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Angular Resource Test</title>
</head>
<body>

    <div ng-controller="MyCtrl">
        <ul>
            <!-- this template is not populated -->
            <li ng-repeat="item in items">{{item}}</li>
        </ul>
    </div>

    <script type="text/javascript" src="bower_components/requirejs/require.js" data-main="scripts/main"></script>
</body>
</html>

My RequireJS is all in main.js, which looks like this:

requirejs.config({
    baseUrl: 'bower_components',
    paths: {
        'angular': '../bower_components/angular/angular',
        'angular-resource': '../bower_components/angular-resource/angular-resource'
    },
    shim: {
        'angular': {
            exports: 'angular'
        },
        'angular-resource': {
            deps: ['angular'],
        }
    },
});

define("app", ["angular", "angular-resource"], function(angular) {
    var app = angular.module('MyApp', ['ngResource']);
    return app;
});

require(["app"], function(app) {
    console.log(app); // this works
    app.controller("MyCtrl", ['$scope', '$resource',
        function($scope, $resource) {
            console.log("hello"); // this doesn't work
            $scope.items = [1, 3, 4, 5];
        }
    ]);
});

It seems that all dependencies are resolved and loaded, and the Angular app is being instantiated. However, I can't register the Angular controller. The console.log() statement inside the callback function isn't executed, so it seems the controller creation fails completely?

/edit:

Adding a ng-app directive to <body> yields this error:

Uncaught Error: [$injector:modulerr] Failed to instantiate module MyApp due to: Error: [$injector:nomod] Module 'MyApp' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.

You can find the complete project on GitHub, if that makes it clearer.

Upvotes: 2

Views: 2362

Answers (2)

Linh Pham
Linh Pham

Reputation: 3025

There is a couple of things that should/may be corrected in your code.

  • Missing angular.bootstrap(document, ['MyApp']);. Because when you use requireJS, angular.bootstrap() is a need. Instead of angular got init right when script load, require got init first. And this it will cause your app crashed. In order to make it work you need to wait require init => then it will load angular up and init angular => after everything done, bootstrap your app.
  • define() supposed to wrapped all code of a module/file
  • require() Use to call a module/file.
  • RequireJS use for seperating your modules into files. So it will be easier to management and possibly improve load time of your app if you config it nicely. By puting a many modules in a files. You just ruined the using purpose of requireJS. (e.g. I have built an app that got the total amount of code, plugins and html at around 3MB. But at the first page loading, it only 400kb, cool heh?)

You can try something like following:

requirejs.config({
    baseUrl: 'bower_components',
    paths: {
        'angular': '../bower_components/angular/angular',
        'angular-resource': '../bower_components/angular-resource/angular-resource',
        'app' : '../scripts/app' // 'app' is the module name. It got defined by define() block, and  can be loaded by either require() or define() block
    },
    shim: {
        'angular': {
            exports: 'angular'
        },
        'angular-resource': {
            deps: ['angular'],
        }
    },
});



require(["app"], function(app) {
    console.log(app);
    app.controller("MyCtrl", ['$scope', '$resource',
        function($scope, $resource) {
            console.log("hello"); // this doesn't work
            $scope.items = [1, 3, 4, 5];
        }
    ]);

    angular.bootstrap(document, ['MyApp']);
});

and inside your app.js

define(["angular", "angular-resource"], function(angular) {
    var app = angular.module('MyApp', ['ngResource']);
    return app;
});

Upvotes: 1

Lee Elenbaas
Lee Elenbaas

Reputation: 305

You have loaded angular, but you have yet to bootstrap it since you load your scripts dynamically, using ng-app attribute is not an option so you need to call

angular.bootstrap(document.body, ['app']);

see https://docs.angularjs.org/api/ng/function/angular.bootstrap

Upvotes: 0

Related Questions