I am trying to inject a few helpers (lodash and a few of my own) in Angular controllers so I have:
angular.module('app').factory("_", Lodash);
Lodash.$inject = ['$window'];
function Lodash($window) {
if ($window._)
return $window._;
}
angular.module('app').factory("_", Helper);
Helper.$inject = ['$window'];
function Helper($window) {
return {
test: function () {
return "test";
}
}
}
So I would like all helpers to be accessible under _ and I would define them in a few JS files ... Can this be done?
With my code only one of them work: lodash methods or test().
For services that don't require dependencies ($window isn't crucial here because it serves for no purpose and can be replaced with window or _ global) config block is a good place to define them, because constant services are already available there.
app.config(function ($injector, $provide) {
var lodash = $injector.has('_') ? $injector.get('_') : {};
angular.extend(lodash, window._);
$provide.constant('_', lodash);
});
app.config(function ($injector, $provide) {
var lodash = $injector.has('_') ? $injector.get('_') : {};
angular.extend(lodash, {
test: ...
});
$provide.constant('_', lodash);
});
When the service is defined this way, its value can be extended several times, the order of config blocks doesn't matter.
Alternatively, service value can be changed with decorator, in order to do that the service should be already defined.
You can not redeclare a factory. As you already noticed, this will overwrite the previous.
You could prepare the helper in separate files and register them in one factory call elsewhere in your app.
Related
I've looked at the documentation for angular.mock.module and a couple of examples of others using it but I seem to be running into an issue in my use-case that I don't understand.
I'm running Jasmine (2.4.1) tests with angular (1.4.9) and I have my angular app separated into multiple modules. When I attempt to mock out certain parts of my app for unit testing I want to mock out entire modules (or providers) so that I only expose the pieces I use.
Here is a very simple app that has a main module plunker which depends on plunker.service. plunker.service depends on plunker.constant.
var app = angular.module('plunker', ['plunker.service']);
app.controller('MainCtrl', function($scope, valueService, appService) {
$scope.init = function() {
$scope.appValue = valueService.getValue();
$scope.appIsRunning = appService.getStatus();
};
});
angular.module('plunker.service', ['plunker.constant'])
.service('appService', function(appSettings) {
var vm = this;
vm.getStatus = function () {
if (appSettings.isRunning) {
return true;
} else {
return false;
}
};
})
.service('valueService', function(valueSettings) {
var vm = this;
vm.getValue = function () {
return valueSettings.value;
}
});
angular.module('plunker.constant', [])
.constant('appSettings', { isRunning: true })
.constant('valueSettings', { value: 10 });
In my Jasmine tests I have a beforeEach() that registers my modules using module (aka angular.mock.module).
I have seen 3 ways of using module
string
function with $provide
object
You can see below that I use the module('plunker') (string) to register my main module and I have 3 ways of mocking out my appSettings constant (A, B, C). You will notice that the function with $provide.constant works fine but function with $provide.value does not and object does not.
beforeEach(function() {
module('plunker');
function useFunction(typeofProvider) {
module(function($provide) {
$provide[typeofProvider]('appSettings', { isRunning: false });
});
}
function useObject() {
module({
appSettings: { isRunning: false }
});
}
// A. THIS WORKS! //
useFunction('constant');
// B. THIS DOES NOT //
// useFunction('value');
// C. THIS ALSO DOES NOT!! //
// useObject();
inject(function($rootScope, $controller) {
$scope = $rootScope.$new();
ctrl = $controller('MainCtrl', {
$scope: $scope
});
});
});
I have also seen people use the following syntax...
beforeEach(function() {
var mockService = function () {
var mockValue = 10;
this.value = mockValue;
};
// D.
module('a.module.name', function newProviders($provide){
$provide.service('realService', mockService);
});
});
My questions
In my test code, why does A. work but B. and C. do not?
Is D. equivalent to calling module('a.module.name'); followed by module(function newProviders($provide) { ... });? Does placing both in the same module() call have any special effects on how things are registered or is it just a shorthand? (based on the documentation it should be a shorthand)
Related to Jasmine, specifically, do all beforeEach() calls run in the same top-to-bottom order with every execution?
Here is my plunker for the above app and jasmine code
Thanks
This happens because of how Angular injector works. In fact, there are two different injectors in Angular. The one (available as $injector in config blocks) deals with service providers. Another one (available as $injector anywhere else) deals with service instances. Providers and instances are cached and stored internally.
$provide.constant('service') creates both provider and instance of name 'service' at call time.
All other types of services are lazily instantiated. They create 'serviceProvider' provider at call time, but 'service' instance is created on the first injection.
Since Angular service instance is a singleton, it refers to instance cache before the instantiation. If the instance is in the cache, it is reused and not instantiated. constant service instance is eagerly instantiated, so only another constant can override the instance.
Object properties in angular.mock.module are shortcuts for $provide.value, and useObject() equals to useFunction('value') in this example.
As long as module order stays the same,
module('a.module.name', function ($provide) { ... });
is indeed a shortcut for
module('a.module.name');
module(function ($provide) { ... });
Due to the fact that appSettings object isn't used in config blocks (the primary use of constant service), it is more convenient to make it value.
When using angularJS you can register a decorating function for a service by using the $provide.decorator('thatService',decoratorFn).
Upon creating the service instance the $injector will pass it (the service instance) to the registered decorating function and will use the function's result as the decorated service.
Now suppose that thatService uses thatOtherService which it has injected into it.
How I can I get a reference to thatOtherService so that I will be able to use it in .myNewMethodForThatService() that my decoratorFN wants to add to thatService?
It depends on the exact usecase - more info is needed for a definitive answer.
(Unless I've misunderstood the requirements) here are two alternatives:
1) Expose ThatOtherService from ThatService:
.service('ThatService', function ThatServiceService($log, ThatOtherService) {
this._somethingElseDoer = ThatOtherService;
this.doSomething = function doSomething() {
$log.log('[SERVICE-1]: Doing something first...');
ThatOtherService.doSomethingElse();
};
})
.config(function configProvide($provide) {
$provide.decorator('ThatService', function decorateThatService($delegate, $log) {
// Let's add a new method to `ThatService`
$delegate.doSomethingNew = function doSomethingNew() {
$log.log('[SERVICE-1]: Let\'s try something new...');
// We still need to do something else afterwards, so let's use
// `ThatService`'s dependency (which is exposed as `_somethingElseDoer`)
$delegate._somethingElseDoer.doSomethingElse();
};
return $delegate;
});
});
2) Inject ThatOtherService in the decorator function:
.service('ThatService', function ThatServiceService($log, ThatOtherService) {
this.doSomething = function doSomething() {
$log.log('[SERVICE-1]: Doing something first...');
ThatOtherService.doSomethingElse();
};
})
.config(function configProvide($provide) {
$provide.decorator('ThatService', function decorateThatService($delegate, $log, ThatOtherService) {
// Let's add a new method to `ThatService`
$delegate.doSomethingNew = function doSomethingNew() {
$log.log('[SERVICE-2]: Let\'s try something new...');
// We still need to do something else afterwatds, so let's use
// the injected `ThatOtherService`
ThatOtherService.doSomethingElse();
};
return $delegate;
});
});
You can see both approaches in action in this demo.
I can access $controllerProvider but can not access $controller in the following method
angular.module(MODULE_NAME, ['common'])
.config(['$routeProvider','$controllerProvider',
function($routeProvider, $controllerProvider) {
console.log($controllerProvider);//defined
console.log($controller);//undefined
}]);
If I use $controller as dependency injection, it is giving
Unknown provider: $controller
But I need to access it, How do I do that
EDIT
I need this because I want to check my controller exists not not. Here is the post where from I am using this code
try {
$controller(controllerName);
listControlerName = MODULE_NAME+'ListController';
} catch (error) {
listControlerName = 'CommonListController';
}
CONTEXT
I am creating architecture of a project. My project structure as follows.
I have one COMMON module. with ListController, EditController, ViewController
I have some other modules like MOD1, MOD2 etc with MOD1ListController, MOD1EditController, MOD1ViewController so on.
Those module specific controller extend corresponding controller from Common Module.
Now my plan is while a new module (MODX) need to be developed, then if there is some extra functionality, then only developer will create a new MODXListController for that module by inheriting common ListController. Otherwise they need not to create any thing.
So system will check if that module contains MODXListController or not. If not then system will use Common ListController.
I do not want to create a MODXListController which inherits common ListController but does not do any extra change. Because I have lots of module nearly 25 and all of then are sharing same functionality mostly.
Without explicitly inheriting all controllers (which is acceptable but verbose solution), a good alternative is to wrap controller switching functionality into mod-controller directive (similar to ng-controller), something like that:
angular.module('common', [])
.constant('MODULE_NAME', 'Common')
.constant('modControllers', [])
.controller('CommonEditController', ...);
.controller('CommonListController', ...);
.directive('modController', function (MODULE_NAME, modControllers) {
return {
restrict: 'A',
scope: true,
priority: 500,
controller: function ($controller, $attrs, $scope) {
var ctrlName = (modControllers.indexOf($attrs.modController) >=0 ? MODULE_NAME : 'Common') + $attrs.modController;
angular.extend(this, $controller(ctrlName, { $scope: $scope }));
});
};
});
angular.module('mod1', ['common'])
.constant('MODULE_NAME', 'Mod1')
.constant('modControllers', ['ListController']);
.controller('Mod1ListController', function ($controller) {
angular.extend(this, $controller('CommonListController');
...
});
When the controller should be specified in application code rather than view (i.e. route and directive controllers), the similar thing can be done with controller factory.
angular.module('common')
.provider('ctrlFactory', function (MODULE_NAME, modControllers) {
function factoryFn(ctrlName) {
return (modControllers.indexOf(ctrlName) >=0 ? MODULE_NAME : 'Common') + ctrlName;
};
this.get = this.$get = factoryFn;
});
It can be injected into directives and used as
...
controller: ctrlFactory('ListController')
Due to the fact that it returns controller name instead of $controller instance and depends only on constant services (MODULE_NAME, modControllers), service provider can also be used in the same way as service instance to declare route controllers in config block:
...
controller: ctrlFactoryProvider.get('ListController')
Because $controller doesn't expose the list of registered controllers, try-catching it comes to mind as automatic solution, and it is the last thing the one may want to do: besides it is a hack, it just suppresses possible exceptions and damages testability.
In .config you can only use providers (e.g. $routeProvider).
In .run you can only use instances of services (e.g. $route).
$controller is of type service which can not be used in .config.
For more detail on this read here.
The detailed discussion on Stack Overflow at this thread shows what can be injected into others.
You can not inject $controller into config
Although you can use the following service to check if your controller is defined.
angular.service('ControllerChecker', ['$controller', function($controller) {
return {
exists: function(controllerName) {
if(typeof window[controllerName] == 'function') {
return true;
}
try {
$controller(controllerName);
return true;
} catch (error) {
return !(error instanceof TypeError);
}
}
};
}]);
Now you can inject ControllerChecker and call its exists(CtrlName) function to check whether your controller is defined or not.
I'm new to AngularJS. Sometimes I see:
angular.module(...)....
Sometimes
var app = angular.module(...)...
Sometimes the latter is wrapped in an IIFE.
When is it appropriate to use either one of the first 2? What real difference do they make?
Most style guides regarding angular recommends the first variant since you never really need to define a variable to reference the module.
You can access a module with angular.module('moduleName') like so:
angular
.module('app')
.controller('SomeController' , SomeController);
function SomeController() { }
I recommend this style guide by John Papa
1st Approach : with
var app = angular.module(...)...
you are saving a reference to the returned module instance and reuse it to register multiple service/configs/providers etc
so you will call methods on this like
app.config();
app.controller();
etc
2nd Approach : with this
angular.module(...)
you are chaining methods with dot in between them because angular.module(...) , contollers, providers returns module instance that can be chained
like
angular.module("sm",[]).config(function(){}).controller()... so on
Comparison/drawbacks/Advantages :
With first approach drawback is that we declare an "app" intermediate variable that could end up in global namespace if we dont use IIFE
(function() {
var app = angular.module(...)...
} )()
So we can use angular.module("...") with each controller/factory etc but that could be much of the repetition
luckily, we can use the second approcach to chain,because angular.module(...) , contollers, providers returns module instance
There is no difference but style you write your project.
Consider following example that demonstrate both cases you mentioned:
angular.module(...)
angular.module('myApp.', [])
.value('version', '0.1')
.service('apiFrontendService', ['$http', function($http) { /* */ }
.factory('localFactory', ['$http', function($http) { /* */ }
.controller('MyController', ['$http', function($http) { /* */ }
and so on. Here we chain our services one after another.
var app = angular.module(...)...
var app = angular.module('myApp.', []);
app.value('version', '0.1');
app.service('apiFrontendService', ['$http', function($http) { /* */ };
app.factory('localFactory', ['$http', function($http) { /* */ };
app.controller('MyController', ['$http', function($http) { /* */ };
Here you define once app and you can use it over all your project
Latter is used to define a global variable to store application's main Angular module. So, code can be splitted into files.
// app.js
var app = angular.module('testApp');
// aController.js
app.controller('aController', ...);
// bController.js
app.controller('bController', ...);
// someService.js
app.service('seriousService', ...);
I am working on an angularJS app and I am trying to stick with the most efficient and widely accepted styles of development in AngularJs.
Currently, I am using this way of declaring my services like so:
app.factory('MyService', function() {
/* ... */
function doSomething(){
console.log('I just did something');
}
function iAmNotVisible(){
console.log('I am not accessible from the outside');
}
/* ... */
return{
doSomething: doSomething
};
});
However, there are numerous examples out there and I am not quite sure which design style to follow. Can someone with extensive knowledge about services explain the reason why a certain style is more relevant than another?
Is what I am doing useful in any way other than restricting the access to certain functions in my service?
I would suggest you layout your factory or service as they do in the angular-seed app, except that app annoyingly only uses value in the services.js boilerplate. However you can adapt the layout they use for controllers, directives and filters.
'use strict';
/* Filters */
angular.module('myApp.filters', []).
filter('interpolate', ['version', function(version) {
return function(text) {
return String(text).replace(/\%VERSION\%/mg, version);
}
}]);
Which means for a service you would do:
'use strict';
/* Services */
angular.module('myApp.filters', []).
service('myservice', ['provider1', 'provider2', function(provider1, provider2) {
this.foo = function() {
return 'foo';
};
}]).
factory('myfactoryprovider', ['myservice', function(myservice) {
return "whatever";
}]);
This has more boilerplate than you absolutely need, but it is minification safe and keeps your namespaces clean.
Than all you have to do is decide which of const, value, factory or service is most appropriate. Use service if you want to create a single object: it gets called as a constructor so you just assign any methods to this and everything will share the same object. Use factory if you want full control over whether or not an object is created though it is still only called once. Use value to return a simple value, use const for values you can use within config.
I don't believe there's an accepted standard but I myself follow this convention:
var myServiceFn = function (rootScope, http) { ... };
...
app.factory('MyService', ['$rootScope', '$http', myServiceFn]);
I feel like this is cleaner than defining the function inline and also allows for proper injection if I ever decide to minify my files. (see http://docs.angularjs.org/tutorial/step_05).
As an example, I've been defining services within modules like so:
angular.module('userModule', [])
.service('userService', function() {
this.user = null;
this.getUser = function() {
return this.user;
};
this.userIsNull = function() {
return (this.user === null);
};
this.signout = function() {
this.user = null;
};
})
I think it is more clear to use the .service rather than the .factory?