Search code examples
angularjsdependency-injectionrequirejsangular-amd

Dependency Injection with Require JS + Angular JS. App requires auth, but auth requires app


I'm trying to load an authService into my application using AngularJS + RequireJS. The app, requires authService to load, and authService requires app to load. But I can't seem to get the load to work properly.

I've tried setting a main controller for the application that will use the authProvider, but if I do that I get the following error:

Error: [$injector:unpr] Unknown provider: authServiceProvider <- authService

If I try to inject the authService into the app, I get this error:

Error: [$injector:modulerr] Failed to instantiate module app due to:
[$injector:modulerr] Failed to instantiate module authService due to:
[$injector:nomod] Module 'authService' is not available! You either misspelled the module name or forgot to load it.

Both errors make sense to me, and I know why they happen. I just don't know if there's a way around it beyond including authService into app.js (which I would like to avoid)

Example code is below.

app.js

define(function (require) {
    var angular = require('angular');
    var ngRoute = require('angular-route');
    var authService = require('authService');

    var app = angular.module('app', ['ngRoute']);

    app.init = function () {
        console.log('init');
        angular.bootstrap(document, ['app']);
    };

    app.config(['$routeProvider', function ($routeProvider) {
        console.log('config');
    }]);

    app.run(function () {
        console.log('run');
    });

    var appCtrl = app.controller('appCtrl', function (authService) {

    });

    return app;
})

authentication.js

require(['app'], function (app) {
    return app.factory('authService', ['$http', function ($http) {
        return {
            test: function () {
                return this;
            }
        }
    }]);
});

config.js

require.config({
    baseUrl:'app',
    paths: {
        'angular': '../bower_components/angular/angular',
        'angular-route': '../bower_components/angular-route/angular-route',
        'angularAMD': '../bower_components/angularAMD/angularAMD',
        'ngDialog': '../bower_components/ngDialog/js/ngDialog',
        'ngCookies': '../bower_components/angular-cookies/angular-cookies',
        'authService': 'services/authentication'
    },
    shim: {
        'angular': {
            'exports': 'angular'
        },
        'angular-route': ['angular'],
        'angularAMD': ['angular'],
        'ngCookies': ['angular']
    },
    priority: [
        'angular'
    ],
    deps: [
        'app'
    ]
});

require(['app'], function (app) {
    app.init();
});

index.html

<!DOCTYPE html>
<html lang="en" ng-controller="appCtrl">
<head>
    <meta charset="UTF-8">
    <title>Document</title>

</head>
<body>
    <div ng-view></div>
    <script src="bower_components/requirejs/require.js" data-main="app/config.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.js"></script>
</body>
</html>

Solution

  • You described a circular reference per "The app, requires authService to load, and authService requires app to load" and there is simply no solution for it.

    However, looking at the sample code you provided, your true dependency is:

    1. authService needs to be created and made available for app
    2. appCtrl created in app requires authService

    Assuming that's your only dependency, you can use angularAMD to create authService:

    require(['angularAMD'], function (angularAMD) {
       angularAMD.factory('authService', ['$http', function ($http) {
            return {
                test: function () {
                    return this;
                }
            }
        }]);
    });
    

    And make sure to use angularAMD to bootstrap app:

    define(['angularAMD', 'angular-route', 'authentication'], function (require) {
        var app = angular.module('app', ['ngRoute']);
        ...
        return return angularAMD.bootstrap(app);
    }]);
    

    Take a look at Loading Application Wide Module for more details.