What is the best practice when you have a Factory with like 4 related methods, each of those is really long (200+ lines of code) and you want to avoid having a huge file of 800+ lines of code?
One solution is to create 4 factories under the same module , each one exposing a single method and in its own file. Then inject all of them in the controller that requires them.
Is there a better solution? I'd like to create the Factory once, then add methods to it like I was doing module augmentation using the module pattern. Then I just need to inject the Factory once and have all its methods available.
I'd like to create the Factory once, then add methods to it like I was doing module augmentation using the module pattern. Then I just need to inject the Factory once and have all its methods available.
Yes, that will work:
// In your main module file.
angular.module('myModule', []);
// file1.js
angular.module('myModule').factory('BigService1', function(){
// Your actual implementation here.
console.log('I am BigService1');
});
// file2.js
angular.module('myModule').factory('BigService2', function(){
// Your actual implementation here.
console.log('I am BigService2');
});
// ... additional files
// Separate file/service to aggregate your big factory services.
angular.module('myModule').service('AggregateService', [
// Add dependencies
'BigService1','BigService2',
function(BigService1, BigService2){
// Return an object that exposes the factory interfaces.
return {
service1: BigService1,
service2: BigService2
};
}]);
You could also arrange your code the old vanilla js style and then access those libraries in your services like this:
var Mirko = { };
Mirko.FunService = {
getAllSomething : function (p1, p2) {
},
...
};
angular.module('myModule').factory('BigService', function(){
return {
methodOne : Mirko.getAllSomething,
...
};
});
You will end up with one object Mirko that you can access outside the scope of your angular app, but it will in no way differ from other externals api's (not written for angular) you would want to use in your app. The way you handle your own 'external' api can be done the oldschool fashion way, one file per 'class' e.g. 'FunService'.
It might not be the prettiest solution but it will be an easy abstraction.
Just saying...
Maybe segment your methods through other factories, which can be injected to your "main" factory :
// file 1
angular.module('foo').factory('segment1', function () {
return {
method: function () {
// ... super long method
}
};
});
// file 2
angular.module('foo').factory('segment2', function () {
return {
method: function () {
// ... super long method
}
};
});
// your main factory file
angular.module('foo').factory('myFactory', function (segment1, segment2) {
return {
method1: segment1.method,
method2: segment2.method
};
}
Related
i am little bit familiar with angular. still on learning process. working with ng version 1.4.8. so i like to know how could i define constructor function in service and factory.
here is one sample service .now tell me how to define constructor in service or factory ?
angular.module('myApp').service('helloService',function($timeout){
this.sayHello=function(name){
$timeout(function(){
alert('Hello '+name);
},2000);
}
});
angular.module('myApp').controller('TestController',
function(helloService){
helloService.sayHello('AngularJS'); // Alerts Hello AngularJS
});
The function you pass to .service gets called with new, thus it is already basically a constructor. It is a "constructor function" and it implicitly returns an object, which is the singleton:
angular.module('myApp').service('helloService',function($timeout){
// This constructor function implicitly returns an object. It is called
// only once by Angular to create a singleton.
this.sayHello = function(name) {
// etc
}
});
Just to illustrate, if you passed an ES6 class to .service (which does have a constructor) instead of a constructor function, that constructor would be called when the singleton is created:
class HelloService {
constructor($timeout) {
// Called once when the singleton is created
}
sayHello(name) {
// etc
}
}
angular.module('myApp').service('helloService', HelloService);
Using .factory is similar, but it doesn't get called with new. So the function you use in this case has to return a singleton object explicitly:
angular.module('myApp').factory('helloService',function($timeout){
// This factory function explicitly returns an object. It is called
// only once by Angular to create a singleton.
return {
sayHello: function(name) {
// etc
}
};
});
Edit: As mentioned by #Vladimir Zdenek, these "constructors" cannot be used to configure the singleton externally. However, I interpreted the question to mean "Where can I put code that runs when the singleton is created?". Singletons may need to initialize data, so that initialization can go in the "constructor".
There is (probably in most cases) no need for a constructor when it comes to singletons. To require such a thing might be just pointing to a bad architectural design of your application.
That said, you can make a global configuration available for your service/factory by using a provider. You can find more on providers in the Official Documentation.
If you do not need a singleton and you wish to create a reusable piece of code, you can use something (in JavaScript) known as factory functions. You can see an example of such function below.
function MyFactory(myParams) {
const Factory = {
// Properties
myProperty: myParams.myProperty,
// Methods
getMyProperty: getMyProperty
};
return Factory;
function getMyProperty() {
return Factory.myProperty;
}
}
// usage
const myObj = MyFactory({ myProperty: 'Hello' });
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.
I'm building a small two-language app with the use of angular-translate. I want to have a language switcher in every view (controller). I'm trying to figure out how to put the code responsible for language switching into every controller. The code looks like this:
var langSwitch = $Scope.setLang = function (langKey) {
$translate.use(langKey);
};
So far I've figured that I can create a factory that looks like this:
app.factory('langSwitch', function ($rootScope, $translate) {
var langSwitch = $rootScope.setLang = function (langKey) {
$translate.use(langKey);
};
return langSwitch;
});
and inject it into controllers in this maner:
app.controller('HomeCtrl', function (langSwitch) {
// normal controller code here
});
This works but 1) I'm using $rootScope and I have a feeling this is bad practice & 2) jsHint screams that "langSwitch" is not defined. Maybe there is a simpler way to make the function global without putting it into every controller?
I'm still pretty new to Angular so don't scream at me :) Thanks.
edit
My view:
<button ng-click="setLang('en_GB')">English</button>
<button ng-click="setLang('pl_PL')">Polish</button>
Although you got the idea, you overcomplicated things a bit. You could declare the service as follows:
app.service('langSwitch', function ($translate) {
this.setLang = function (langKey) {
$translate.use(langKey);
};
});
And then inject langSwitch in the controller responsible for lang switching, as you already did. No need to inject $rootScope in the service.
You don't need $rootScope indeed unless you need to process some global events in your application. All services and factories in angular are singletons by default. That means once it created, it will be passed as the same instance in every place it is declared as a dependency. So if you want to share data and functionality between different controllers - the services will suit fine. You can change your factory code to:
app.factory('langSwitch', function($translate) {
return {
setLang: function(langKey) {
$trasnlate.use(langKey);
};
};
});
I just went through a code where the programmer has created an array of controllers and then added the array to a module.
Following is the type of code :-
// the array of controllers
var controllers = {};
//adding a controller to array
controllers.ExampleController1 = function(){};
controllers.ExampleController2 = function(){};
//adding the controllers to module
var ABCmodule=angular.module('ABCmodule',[]);
ABCmodule.controller(controllers);
I realized that the controller array is made in global scope. Isnt that dangerous? Moreover is this good style of coding. I prefer only making one variable for module and adding all controllers inside that module. What is the best way to do this?
This particlar setup can be solved by:
for (var ctrl in controllers) {
if(controllers.hasOwnProperty(ctrl)) {
ABCmodule.controller(ctrl);
}
}
That being said, why not just add controllers directly to module which would be declared first? Also loop can be simplified using lodash's _.forOwn()
angular
.module('abc', [])
.controller('ctrl1', ctrl1)
.controller('ctrl2', ctrl2); // ...
function ctrl1() {
}
function ctrl2() {
}
Angular does this internally all the time, but you don't have to accept its source code style as paragon. It is ok while you keep the variables inside IIFE.
If you want to keep the style in ng vein, you can do like this:
ctrlModule.config(function ($controllerProvider, controllers) {
angular.forEach(controllers, function (constructor, name) {
$controllerProvider.register(name, constructor);
});
});
ctrlModule.constant('controllers', { ... });
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?