how can I create a helper/utility class that can be accessible from the multiple controllers?
For example, I have two controllers: UpdateItemCtrl and CreateItemCtrl. These have common functions inside which increases redundancy and lowers managability.
I'd like to create a ItemSaveHelper class which I would put the common methods inside and call them from the active controller.
You want to create a service.
A service is just a singleton that can be injected into different things to provide modular/shared functionality. Here's a simple example: http://jsfiddle.net/andytjoslin/pHV4k/
function Ctrl1($scope, itemManager) {
$scope.addItem = function(text) {
itemManager.items.push(text);
};
}
function Ctrl2($scope, itemManager) {
$scope.items = itemManager.items;
}
app.factory('itemManager', function() {
return {
items: []
};
});
Related
I have a service which will return the name of factory. I already injected all the factories into controller. I need to use the variable to call the method inside that factory. I know i can use
if(var == 'factoryname') {
factoryname.method()
}
but i don't want those if conditions because i have number of factories. Is there any way to call a method inside that factory like in java script
window[var]
You should consider storing all of your factories on an object:
var factories = {
factoryA: { method: function() {} },
factoryB: { method: function() {} },
};
var factory = 'factoryA';
factories[factory].method();
I have one BaseController with common functions which my all other controllers inherit .
The controller is like this
function BaseController () {
this.defaultFilters = {};
this.doStuff = function ($scope) {
$scope.myobj.value = 1;
this.otherfunction();
};
I inherit that in my controller like this
BaseController.call($scope);
Now in my do stuff function i need to pass $scope because myobj is only visible there.
Now i want to know that how can i pass that in my template because i want to call that function when some click on some button
ng-click="doStuff(scope)"
Everything that you associate with your controller's scope, so you just associate your scope with some variable and i guess that will do the job.
Something like this :
app.controller(function($scope) {
$scope.scope = $scope;
});
But if you go by some standard approach, i suggest moving these common functions inside some service, injecting this service into each controller and using it in the views.
Something like this :
app.service("constantService", function() {
this.data = {}; // This will represent your common data.
this.commonFunction = function() {
};
});
app.controller(function() {
$scope.constantService = constantService;
// You can now use $scope.constantService.data as your reference for data, and then can copy it to some local $scope variable whenever required.
});
ng-click="constantService.commonFunction()"
So I have a tree helper object in my angular app that provides a bunch of useful functions for dealing with the many tree structures in the app. This is provided by a factory, so each time some controller (or whatever) asks for a tree helper, it gets its own copy:
angular.module('MainApp').factory('TreeHelperFactory',
function ($http, $q, $filter, DataService) {
var treeHelper = new function ($http, $q, $filter, DataService) {
...
code
...
})
Now I have a category service that provides various category-related functions, including returning a tree of categories and providing ways to manipulate that tree. So thinking like an OO developer, I reckon that the category service is really like a subclass of my tree helper, so I inject a tree helper instance and then attempt to extend that instance with category-specific functions, naively like this:
angular.module('MainApp').provider('CategoryService',
function() {
this.$get = function ($http, $q, $filter, DataService, TreeHelperFactory) {
var catService = TreeHelperFactory;
catService.listCategories = function() {...}
catService.deleteCategory = function(id) {...}
... more code...
return catService;
}
}
);
But this doesn't work. The new properties are not visible when I try to invoke them later, only the tree helper properties of the original factory object. What am I missing and how do I achieve this?
Services in angular.js are singletons, which means each time you inject a service it returns the exact same object, you cannot force it to return a new object each time it is injected.
What you can do is to create a Class function, for example:
angular.module('MainApp')
.factory('TreeHelperFactory',
function ($http, $q, $filter, DataService) {
/**
* TreeHelper constructor
* #class
*/
function TreeHelper() { /* this.init(); */ }
/**
* TreeHelper static class method
*/
TreeHelper.list = function() { /* ... */ };
/**
* TreeHelper instance method
*/
TreeHelper.prototype.init = function() { /*...*/ };
/**
* Returns the class
*/
return TreeHelper;
})
Now you can inject it, instantiate an object and extend it like so:
.factory('CategoryService', function (TreeHelperFactory) {
var catService = new TreeHelperFactory();
catService.listCategories = function() { /*...*/ };
catService.deleteCategory = function(id) { /*...*/ };
return catService;
});
You can also use javascript prototypical inheritance but I think it's an overkill for most cases so keep it simple if you can.
Helper that depends on Angular services is a bad smell for me - almost like its status is more than a helper and it has a service or two in it. Would you be able to rethink this through restructuring their roles and responsibilities?
From my understanding factories are an abstraction over Angular's providers, which allow you to return data with less lines of code. However, providers provide more flexibility in that you can better define the service's functionality. I'm still really confused on how to call a simple function from a provider. Everyone seems to be doing them differently and I cannot get mine to work:
myApp.provider('myProvider', function() {
myVar = true;
$get: function() {
return {
myVar: myVar,
}
},
toggleFalse = function() {
myVar = false;
},
})
myApp.controller('myController', function($scope, myProvider) {
myProvider.toggleFalse();
});
This does not seem to work - and I'm having trouble understanding services in general. It says toggleFalse is not defined. How do you properly define a setter function on an Angular service that can be controlled through a controller?
If you do console.dir(myProvider), you'll see that you are getting the object returned from $get. You need to put the function on the returned object:
$get: function() {
return {
myVar: myVar,
toggleFalse: function() {
myVar = false;
},
}
},
This is a simple question of closure.
If you want every instance to have a unique everything, then store everything inside $get.
If you want the majority of the object to be unique, but have some methods or objects/arrays that every instance shares with each other, then define those in the function closure outside of $get and append them to the object returned from $get.
... ("myProvider", function () {
var sharedValue = 19,
sharedFunction = function () {
sharedValue += 1;
return shared value;
};
return {
$get : function () {
return {
unique : 1,
shared : sharedFunction
};
}
};
This isn't an Angular issue, so much as a core piece of JS's behaviour, which happens to be inside of an Angular paradigm.
In my application,I have to build a standalone lib for other people use,so I create new object like this:
function MyService(){
//xxxxxxx...
}
MyService.prototype.login=function(name,pass){
//here
}
MyService.prototype.LoadDataFromServer(){
//use the ajax get data from server,when get the data,I will eval them :
var data=parseData(request.responseText);
//now,the parseData is a private method which should not be exposed to the user,but it need the reference of the MyService object(this),so I have to use the following code:
var this_ref=this;
function parseData(res){
this_ref.xxxx=.....
}
}
MyService.prototype.parseData=function(res){
this.xxxxx=....
}
This will make the paresData function to the user.
Now,I wonder which is better?
If you want actually private data/methods you should be using closures better.
var MyService = (function() {
// define "private" methods
var _login = function(name, pass) {
...
},
_loadDataFromServer = function() {
....
},
_parseData = function(res) {
...
};
//return "public" methods
return {
login: _login,
loadDataFromServer: _loadDataFromServer
};
}()); // execute function immediately
MyService now only has the two "public" functions, login and loadDataFromServer you can still access the "private" functions from the public functions but you cannot directly access any of the "private" methods MyService._login('test','pass'); will fail but MyService.login('test','pass'); will work. See this example http://jsfiddle.net/EXrDW/
There is no "better" answer, only what you feel more comfortable with. What a lot of people seem to have adopted is the practice of putting underscores in front of methods that shouldn't be accessed by users.