I have controller (say BaseCtrl) that has a number of functions attached to it. I want to extend BaseCtrl to other controllers that shares some of its functions, however, I only need a function or two (and not all of BaseCtrl's functions). I already saw some posts that demonstrates how to extend a controller, but I wonder if it's possible to extend specific functions only and how to do it?
Extending my comment:
app.controller('parentCtrl', function($scope,$rootscope) {
$rootscope.myPerent = function () {
//your code
}
});
app.controller('childCtrl', function($scope,$rootscope) {
$scope.ourPerent = function () {
$rootscope.myPerent();
}
});
Related
My controller is getting somewhat busy and finding the function that I'm looking for is becoming cumbersome. I'd like to have individual files for some of my controller functions. How can I achieve this? Is there something like ng-include for the controller to use?
You might use the mixin pattern. This allows you to extend your controllers with other controllers. As a result you have now two different controllers, while both get executed at the same time:
app.controller('AnyController', ['$scope'
function ($scope) {
return {
myFunction: function() {
// do something
}
}
}
]);
app.controller('MyMainController', ['$scope'
function ($scope) {
var anyThing = $controller('AnyController as anyThing',{$scope: $scope}),
$scope.anyThing = function() {
// those two options are now both valid:
anyThing.myFunction();
$scope.anyThing.myFunction();
}
}
]);
Now you are able to move your seperate controllers into different files.
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.
Consider the following example:
angular.module('demo')
.service('MyService', function () {
this.fn = function () {
console.log('MyService:fn');
};
})
.factory('MyFactory', function () {
function fn() {
console.log('MyFactory:fn');
}
return { fn: fn };
})
.value('MyValue', {
fn: function () {
console.log('MyValue:fn');
}
})
.constant('MyConstant', {
fn: function () {
console.log('MyConstant:fn');
}
})
.run(function (MyService, MyFactory, MyValue, MyConstant) {
MyService.fn();
MyFactory.fn();
MyValue.fn();
MyConstant.fn();
MyService.fn = undefined;
MyFactory.fn = undefined;
MyValue.fn = undefined;
MyConstant.fn = undefined;
})
.run(function (MyService, MyFactory, MyValue, MyConstant) {
MyService.fn();
MyFactory.fn();
MyValue.fn();
MyConstant.fn();
});
When the first run() is executed, all 4 console logs will be executed and print something on the console. Then I set each of the providers fn function to undefined for simplification purposes, say someone rewrote this function somewhere (which is something I want to prevent).
On the second run() block, everything is undefined and errors will be thrown. I'm confused by this... Shouldn't at least some of them (constant is the first to come to mind) be immutable objects?
Is this the expected behavior or am I doing something wrong?
Why is this a surprise. Angular is a framework running on top of Javascript, and Javascript is a dynamic language. Your question is really about the language construct.
First, recognize that all the calls are, at the end of the day, registering a provider that would return an object to be injected. .service, .factory, and .value are just short hands for .provider (.constant is a bit different).
Having established that there is no difference between them once the object is injected, all you then need to concern yourself with is how to make that object immutable.
Javascript provides Object.freeze function, so for example, you could do:
var immutable = {
fn: function () {
console.log('MyConstant:fn');
}
};
Object.freeze(immutable);
app.constant("MyConstant", immutable);
The functions constant, factory, service etc. allow you to create Javascript objects that are created once, then cached by angular, and injected into components as/when needed. Because these are Javascript objects, then (ignoring the possibility of using freeze) any bit of code has access to these objects can modify properties on them, as you have demonstrated.
Although properties on the objects themselves can be modified, the object itself can't be changed to another one, so if you really want an immutable provider, that is safe from all tampering, one way that I can think of is to use a factory that returns not an object, but a getter function:
app.factory('MyFactory', function() {
var functions = {
myFunctionName: function() {
}
};
return function(functionName) {
return functions[functionName];
};
});
which can be used, say in a controller, as
app.controller('MyController', function(MyFactory) {
MyFactory('myFunctionName')();
});
A drawback of using this over the more traditional way of exposing all the methods and allowing the possibility of the object to be modified is that I suspect unit testing could be more complicated: you wouldn't be able to easily create spies on your factory methods by using createSpy(MyFactory, 'myFunctionName').
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
};
}
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?