Angular + Requirejs - how to return multiple modules? - javascript

How can I return multiple angular modules in requirejs environment?
this is my app.js,
define([
'angular',
'angular-route',
'jquery'
], function (ng,ngRoute,$) {
'use strict';
console.log($('h1').length);
return ng.module('myApp', ['ngRoute']);
});
And I need a few more modules to return,
ng.module('myAppModule1', ['ngRoute']);
ng.module('myAppModule2', ['ngRoute']);
ng.module('myAppModule3', ['ngRoute']);
a controller example, for instance I want to get 'myAppModule3' in app.js,
define(['app'], function (app) {
var myAppModule = angular.module('myAppModule3');
myAppModule.controller('welcomeController', ['$scope', function($scope) {
//your minsafe controller
$scope.message = "Message from WelcomeController";
}]);
});

You could change app.js to return an object whose fields are the modules:
define([
'angular',
'angular-route',
'jquery'
], function (ng,ngRoute,$) {
'use strict';
console.log($('h1').length);
return {
myApp: ng.module('myApp', ['ngRoute']),
myAppModule1: ng.module('myAppModule1', ['ngRoute']),
myAppModule2: ng.module('myAppModule2', ['ngRoute']),
myAppModule3: ng.module('myAppModule3', ['ngRoute'])
};
});
And change your controller like this:
define(['app'], function (app) {
app.myAppModule3.controller('welcomeController', ['$scope', function($scope) {
//your minsafe controller
$scope.message = "Message from WelcomeController";
}]);
});

The generic (non-Angular specific) way is to use an object:
return {module1: /*..*/, module2: /*...*/ };
Then you just access to the values:
define(['app'], function (app) {
var module1 = app.module1;
});
However in Angular you just registered 'myAppModule1' in the Angular global. There is no need to do the object return, you can retrieve the registered module using the angular object:
define(['angular'], function (angular) {
var module1 = angular.module('myAppModule1');
// without extra parameter it tells angular to retrive an existing
// module
});
Update: I just realize that you did it in your code. It didn't worked? Maybe be you have a dependency issue, make sure that app.js is loaded first.

Related

How to resolve dependencies for a project using AngularJS and RequireJS?

I have a simple AngularJS application which I am trying to refactor to use RequireJS.
Since controllers and services are loaded async, I can't use ng-app in my index.html.
Following is my main.js
require.config({
paths: {
"angular": '../../bower_components/angular/angular',
"angularCookies": '../../bower_components/angular-cookies/angular-cookies'
},
shim: {
angular: {
exports: "angular"
},
angularCookies : {
deps: ["angular"]
}
}
});
require(['angular', './login/js/login'],
function (angular) {
angular.bootstrap(document, ['loginApp']);
}
);
My login.js is where I am defining an angular module.
Following is my login.js
'use strict';
define(['angular',
'angularCookies',
'./login.controller'],
function(angular, angularCookies, loginController) {
angular.module('loginApp', [
'ngCookies'])
.config(['$cookiesProvider',
function($cookiesProvider) {
$cookiesProvider.defaults.path = '/';
$cookiesProvider.defaults.domain = 'localhost';
}
])
.run(['$cookies',
'loginService',
function($cookies, loginService) {
}
]).controller(loginController);
});
As seen, it is dependent on loginController and loginController is dependent on loginService.
My loginService is defined as --
"use strict";
define(['angular',
'angularCookies'],
function (angular, angularCookies) {
var loginService = angular.module('loginApp')
.factory('loginService', [
'$http',
'$cookies',
function ($http, $cookies) {
// My functions and other code here.
}]);
return loginService;
});
With this configuration I am getting an error -
Module 'loginApp' 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.
What am I missing here?
What configuration do I need to do to make it right?
I see a couple of problems. First the app shouldn't be created inside login. The app is the base of all controllers and services.
So I would move the app creation to another file called app.js.
Then in my require config:
shim: {
'app': {
deps: ['angular', 'angular-route', 'angularCookies']
},
angularCookies : {
deps: ["angular"]
}
}
And:
require
(
[
'app'
],
function(app)
{
angular.bootstrap(document, ['loginApp']);
}
);
And then your controller would be:
define(['loginApp'], function(app)
{
app.controller('loginController',
[
'$scope',
function($scope)
{
//...
}
]);
});

Dealing With Dependencies in angularjs Testing

This is for work (I have permission) so I can't post exact code.
So I have to test controllers of a large module. The module has a large config function with a bunch of controllers for the logic of the different pages.
For the actual application it's loaded with bower, which is irritating since I'm testing with Karma-Browserify and npm. So the the dependencies are a mess. I basically have to import everything that was loaded from bower.json to package.json.
This is my karma.conf.js:
module.exports = function(config) {
config.set({
basePath: 'resources',
browserify: {
debug: true,
transform: [ 'browserify-shim' ]
},
browsers: [ 'PhantomJS' ],
captureTimeout: 60000,
client: {
mocha: {}
},
files: [
'tests/assist/test.js',
'assets/scripts/libs/logger.min.js'
],
frameworks: [ 'browserify', 'phantomjs-shim', 'mocha', 'chai' ],
port: 8080,
preprocessors: {
'tests/assist/controller.js': [ 'browserify' ]
},
reporters: [ 'mocha', 'coverage' ],
singleRun: true
});
};
So the code below this is my test.js (removing some company-specific names). Also I need to put angular.mock. or it won't work
require('angular');
require('angular-mocks');
//Main module needs these
jQuery = require('jquery');
require('angular-bootstrap');
require('angular-recaptcha');
require('angular-ui-router');
require('ngstorage');
require(**The path to the main module**);
require(**The path to a service it uses**);
require(**The path to a service it uses**);
require(**The path to a service it uses**);
describe('Blah', function () {
beforeEach(angular.mock.module('myApp'));
var $controller;
beforeEach(angular.mock.inject(function(_$controller_) {
$controller = _$controller_;
}));
describe('blahblah', function () {
it('sets loading to true', function () {
var $scope = {};
var controller = $controller('controller', {$scope: $scope});
assert($scope.showLoading === true);
});
});
});
The main module:
(function() {
'use strict';
})();
// Jquery noconflict
jQuery.noConflict();
var myApp = angular.module('myApp', ['ui.router', 'ngStorage', 'vcRecaptcha', 'ui.bootstrap']);
myApp.config(['$stateProvider', '$urlRouterProvider', '$locationProvider', function($stateProvider, $urlRouterProvider, $locationProvider) {
...
}])
.run([blah bunch of dependencies]) {
...
}]);
The controller (separate fie):
'use strict';
myApp.controller('controller', ['$scope', '$http', '$localStorage', 'service1', 'service2', 'service3',
function ($scope, $http, $localStorage, service1, service2, service3) {
..
}
...
As you can see I'm in dependency hell. I got the example test on the angular site to work, the main problem is with the dependencies and myApp not being visible to the controller. "ReferenceError: Can't find variable: myApp" in controllers/services
If anyone has a better way of going about testing I'm all ears.
This is not about dependency hell, not about testing also.
The code seems to rely on myApp global variable, this is strictly opposite to what Angular modules are for.
myApp should be a local variable that is defined dynamically in each function scope
(function () {
var myApp = angular.module('myApp', [...]);
...
})();
(function () {
var myApp = angular.module('myApp');
myApp.controller('controller', ...)
...
})();

AngularJS controller does not run on RequireJS config

I am trying to configure an web app with requireJS and angularJS. I come from marionette configuration and I am trying to have a similar one in angular (in concepts like views and controllers) first so I want to be able to map #/test to my controller and log in the console one message.
I've seen Does AngularJS support AMD like RequireJS? and RequireJS and AngularJS and I kind of got the differences and from my point of view my config should work... but it does not...
Here is my code:
File: app.config.js
require.config({
shim: {
angular: {
exports: 'angular'
},
angularRoute: ['angular']
},
paths: {
angular: '../lib/angular',
angularRoute: '../lib/angular-route'
}
});
require(['angular', 'app', 'routes/index'], function (angular) {
angular.bootstrap(document, ['app']);
});
File: app.js
define(['angular', 'angularRoute'], function (angular) {
//angular.module('app.controllers', []);
var app = angular.module('app', ['ngRoute']);
return app;
});
File: routes/index.js
define(['angular', 'app', 'controllers/index'], function (angular, app) {
app.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/', { templateUrl: require.toUrl('/resources/js/app/templates/test.html'), controller: 'indexController'});
}]);
});
File: controllers/index.js
define(['angular', 'app'], function (angular, app) {
//var appControllers = angular.module('app.controllers');
app.controller('indexController', ['$scope', function ($scope) {
console.log('cascade...');
}]);
});
What am i missing? When i access #/test, i don't see "cascade" in the console, should I?.. Right?
Thanks in advance.

Error: Unknown provider - Karma, requirejs, angular

I get this error when i try to make a test
Error: [$injector:unpr] Unknown provider: $translateProvider <- $translate
I'm using karma with requirejs.
loadingCtrlSpec.js
define([
'angular',
'angular-mocks',
'app',
'angular-translate'
], function(angular, mocks, app) {
'use strict';
describe('loadingCtrl', function(){
var ctrl, scope, translate;
beforeEach(mocks.module('TestApp'));
beforeEach(inject(function($injector){
scope = $injector.get('$rootScope').$new();
translate = $injector.get('$translate');
}));
it("contains spec with an expectation", function() {
expect(true).toBe(true);
});
});
});
loadingCtrl.js
define(['angular'], function (angular) {
'use strict';
angular.module('TestApp', [])
.controller('loadingCtrl', ['$scope', '$translate', function($scope, $translate) {
$translate(['build.DEFAULT_EMAIL_SUBJECT','build.DEFAULT_EMAIL_NOTES']).then(function (translations) {
$scope.title = translations["build.DEFAULT_EMAIL_SUBJECT"];
$scope.notes = translations["build.DEFAULT_EMAIL_NOTES"];
});
}]); })
If i don't use angular-translate ($translate) everything is working so i don't think the problem is from karma.conf.js or test-main.js (require.conf for karma).
Your TestApp module will need to specify the pascalprecht.translate module as a dependency. Also be sure to include angular-translate as a dependency when defining your main module so the relevant script gets loaded:
define(['angular', 'angular-translate'], function (angular) {
angular.module('TestApp', ['pascalprecht.translate']);
});

RequireJS and AngularJS multiple controllers

I'm using latest version of Require and Angular, but i encountered strange bug. I have controller for every view, but apparently works only for one view. This is my example code:
Define all controllers: Controllers.js
define([
'modules/index/controller',
'modules/test/controller'
], function(){});
Here works only with one controller, if i include 2 like here i get Error: ng:areq
Bad Argument
Index: controller.js
define(['angular'], function(angular){
'use strict';
return angular.module('myApp.controllers', [])
.controller('indexCtrl', ['$scope' , function ($scope){
alert("index ok");
}]);
});
Test: controller.js
define(['angular'], function(angular){
'use strict';
return angular.module('myApp.controllers', [])
.controller('testCtrl', ['$scope' , function ($scope){
alert("test ok");
}])
});
Where i'm wrong?
The problem is that you are creating the myApp.controllers module twice and one is overwriting the other. Assuming that you are manually bootstrapping angular after loading the controller, what you should be doing is to create the module first, then load that module to create controller:
app.js
define(['angular'], function(){
'use strict';
return angular.module('myApp.controllers', []);
});
Index: controller.js
define(['app'], function(app){
'use strict';
return app.controller('indexCtrl', ['$scope' , function ($scope){
alert("index ok");
}]);
});
Test: controller.js
define(['app'], function(app){
'use strict';
return app.controller('testCtrl', ['$scope' , function ($scope){
alert("test ok");
}])
});
I created angularAMD to facilitate use of RequreJS and AngularJS that might be of interest to you:
http://marcoslin.github.io/angularAMD/

Categories