Inject Angular service to controller only if it needed - javascript

I try implement lazy loading of angular services, controllers, directives, filters, I found way to do something similar using RequireJS. But I cant`t found how to load service into controller dynamically only when it is needed.
My controller:
require(["app"], function (app) {
app.controller('dialogsCtrl',function($scope,dialogsSer){
$scope.tooltip = function(){
dialogsSer.tooltip(); // work ok
}
...
I want to implement something like (also to still possibility inject service as angular inline way):
require(["app"], function (app) {
app.controller('dialogsCtrl',function($scope){
$scope.tooltip = function(){
// load service only if tooltip function is called
require(["dialogsSer"], function (dialogsSer){
dialogsSer.tooltip();
);
}
...
require config:
require.config({
baseUrl: ...,
paths: {
....
'dialogService':'resources/web/app/services/dialogsSer',
...
deps: ['app']
});
Dialogs servise:
require(["app","directives"], function (app) {
app.service('dialogsSer', function($http,$uibModal){
var ds = {};
...

I found angular $injector method for insert service on run time.
require(['dialogService','userSer'],function(){
if(!$rootScope.userSer)$rootScope.userSer = $injector.get("userSer");
if(!$rootScope.dialogsSer)$rootScope.dialogsSer = $injector.get("dialogsSer");
$scope.$apply();
});

Related

angular js : Is it necessary to load all the controllers and factories / services in module file

NET MVC to one CRM application and using angular js for client side script.
I have come across several articles to use angular js and all of them have set controller and services / factories inside the module and they are loaded all in one time.
So my question is it necessary to load all controllers and services in module or I can separate those js and use in page by page whenever I need to use page wise?
I am navigating using ASP.NET MVC pattern not single page using angularjs route.
Yes you can separate those angularjs files and use one angularjs controller per page, but you need to register the modulename of the controller or service in the main module(app.js) inside the brackets[], like this:
//app.js
var app = angular.module('myApp', ['ngRoute','myApp.controller','myApp.create.controller'])
.config(function ($routeProvider,$locationProvider) {
$routeProvider
.when("/", {
templateUrl: 'home/home.html',
controller: 'HomeController',
controllerAs: 'home'
}).when("/create",{
templateUrl: 'manage/create.html',
controller: 'CreateController',
controllerAs: 'create'
})
});
//HomeController.js
var module = angular.module('myApp.controller', ['myApp.service']);
module.controller('HomeController', ['HomeService',
function (HomeService) {
var self = this;
self.EmpData = [];
HomeService.getAllEmployeesTable().then(onSuccess, onError);
function onSuccess(response) {
self.EmpData = response.data;
}
function onError(error) {
alert('Error fetching data');
}
}]);
//CreateController.js
var module = angular.module('myApp.create.controller',['myApp.create.service']);
module.controller('CreateController',['CreateService',
function(CreateService){
var self =this;
self.person = {
name : "", email:"",address:"",telephone:""
}
self.submitPerson = function(){
console.log(self.person);
CreateService.submitPerson(self.person).then(onSuccess,onError);
}
var onSuccess = function(response){
alert("User has been added succesffully");
}
var onError = function(error){
alert("Error creating person");
}
}
]);

Error: inject Angular $http service into requires plugin

I want to use AngularJS $http service in my custom requireJS plugin. The following is my code.
I can see angular module in my plugin "foo", but I don't know how to get $http service from the angular module.
Could anybody give me some direction? Thx in advance.
main.js
require.config({
waitSeconds : 20, //make sure it is enough to load all scripts
paths: {
cordova: '../lib/js/ng-cordova',
angular: '../lib/js/angular/angular', // <---- here is angular
angularAnimate: '../lib/js/angular/angular-animate',
angularTouch: '../lib/js/angular/angular-touch',
angularSanitize: '../lib/js/angular/angular-sanitize',
uiRouter: '../lib/js/angular-ui/angular-ui-router',
ionic: '../lib/js/ionic.bundle',
ionicServiceCore: '../lib/js/ionic-core',
angularIonic: '../lib/js/ionic-angular'
}
}
foo.js
define(['angular'],function(angular){
return {
load: function(name,req,onLoad,config){
console.log(angular);
//
// I want to use $http here
// but how to retrieve $http from angular module???
//
} // load
};
});
You should be able to get $http service with this code:
define(['angular'], function(angular) {
return {
load: function(name, req, onLoad, config) {
var $http = angular.injector(['ng']).get('$http');
// $http.get(...).then(...)
}
};
});

Angular + Requirejs - how to return multiple modules?

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.

Splitting AngularJS Module Services Across Files

I have two AngularJS services:
service1.js
'use strict';
angular.module('myModule', [])
.factory('myService1', function() {
return {
myFunction: function(options) {
if (options) {
// do stuff
}
}
};
});
service2.js
'use strict';
angular.module('myModule', [])
.factory('myService2', function() {
return {
myFunction: function(options) {
if (options) {
// do stuff
}
}
};
});
I learned the hard way from the official docs that this approach will basically remove myService1 because the module gets overwritten. My question is, do I have any options here? I would really like to be able to have my services defined in separate files. Yet, I only want one module.
Thank you for any insights.
You have to define the module just once:
angular.module('myModule', []);
And then use it as many times as you need it without setting the dependencies:
angular.module('myModule');
So either you define the module in a separate file, or if you define it in the first service, the second should look like this:
angular.module('myModule')
.factory('myService2', function() { ... });

Unit testing AngularJS lazy-loaded controller

I am using this strategy to lazy-load stuff with RequireJS in my AngularJS app:
define([
'src/services/dependency_resolver', // resolves promise when dependencies are `require`d
'json!modules.json'
], function (dependencyResolver, modules) {
var app = angular.module('myApp', [ 'ngRoute' ]);
app.config(function ($controllerProvider, $routeProvider) {
app.lazy = {
controller: $controllerProvider.register
// <...> other providers
};
angular.forEach(modules, function (moduleConfig) {
angular.forEach(moduleConfig.routes, function (route) {
$routeProvider.when(route.path, {
templateUrl: route.templateUrl,
controller: route.controller,
resolve: dependencyResolver(moduleConfig.dependencies)
});
});
});
});
return app;
});
But I'm not sure what is the correct way test a lazy-loaded controller. It is registered like this:
define(['src/app'], function (app) {
app.lazy.controller('MainCtrl', function () {
//
});
});
And this is my current spec:
describe('`MainCtrl` controller', function () {
var Ctrl,
$scope;
beforeEach(angular.mock.module('myApp'));
beforeEach(function (done) {
require(['module/main'], done);
});
beforeEach(function () {
angular.mock.inject(function ($rootScope, $controller) {
$scope = $rootScope.$new();
Ctrl = $controller('MainCtrl', {
$scope: $scope
});
});
});
it('should ...', function () {
console.log(Ctrl);
});
});
With this spec, an error occurs when controller is being registered, because app.lazy is undefined.
So the question is how to test such controllers?
Cheers!
I was experiencing a similar problem when writing my unit test using the "lazy" property to register my controller. The problem with this approach is that when in the context of a unit test, the module config block will not be executed and as a result, app.lazy will resolve to undefined.
To solve your problem, instead of using provider registration methods to set your properties of app.lazy, the provider registration method should be used to override their counterparts on the module. In other words, your config block should now become:
`app.config(function ($controllerProvider, $routeProvider) {
app.controller = $controllerProvider.register
// <...> other providers
.......
}`
Instead of register your controller using (app.lazy):
`define(['src/app'], function (app) {
app.lazy.controller('MainCtrl', function () {
//
});
});`
you can just define like this:
`define(['src/app'], function (app) {
app.controller('MainCtrl', function () {
//
});
});`
And this should work! Hopefully this can help, and please let me know if this works out or not.
First of all, thank you for the reference you provided - the article is really interesting.
Author of the article is using AngularJs providers to implement his strategy. The thing is, that AngularJs doesn't have providers for 'specs'. So my opinion is that you should omit this strategy in your unit tests.
On this basis, I think, that you should add AMD to your spec file. Define your controller as a dependency in your spec. After this, you may just require all your specs somewhere in main-spec.js and launch your testing framework.

Categories