What is the way to create private methods in an AngularJS controllers?
I have currently done it like this, but I wonder whether it is the correct/preferable way:
app.controller('MyController', function($scope){
myPrivateFunction();
anotherPrivateFunction();
...
$scope.someScopeMethod = function(){
...
anotherPrivateFunction();
...
};
$scope.anotherScopeMethod = function(){
...
myPrivateFunction();
...
};
...
function myPrivateFunction(){
//
}
function anotherPrivateFunction(){
//
}
});
This is correct. Your functions will only be visible inside the scope of your controller constructor function. This is the same for factories and vanilla js where functions declared in functions will only be visible in their parent function context.
In factories it would looks like as below:
.factory('my-factory', function(){
function privareMethodA() {
}
var anotherPrivateMethod = function() {
}
return {
publicMethodA = function() {
},
publicMethodB = function() {
}
};
});
So after you inject your factory into another factory or a controller publicMethodA() and publicMethodB() will be available, but privateMethodA() and anotherPrivatemethod() won't be accessible from outside of this factory.
Accessibility of controllers are similar to your snippet.
Related
I need to execute functions of some controllers when my application ends (e.g. when closing the navigator tab) so I've thought in a service to manage the list of those functions and call them when needed. These functions changes depending on the controllers I have opened.
Here's some code
Controller 1
angular.module('myApp').component('myComponent', {
controller: function ($scope) {
var mc = this;
mc.saveData = function(objectToSave){
...
};
}
});
Controller 2
angular.module('myApp').component('anotherComponent', {
controller: function ($scope) {
var ac = this;
ac.printData = function(objects, priority){
...
};
}
});
How to store those functions (saveData & printData) considering they have different parameters, so when I need it, I can call them (myComponent.saveData & anotherComponent.printData).
The above code is not general controller but the angular1.5+ component with its own controller scope. So the methods saveData and printData can only be accessed in respective component HTML template.
So to utilise the above method anywhere in application, they should be part of some service\factory and that needs to be injected wherever you may required.
You can create service like :
angular.module('FTWApp').service('someService', function() {
this.saveData = function (objectToSave) {
// saveData method code
};
this.printData = function (objects, priority) {
// printData method code
};
});
and inject it wherever you need, like in your component:
controller: function(someService) {
// define method parameter data
someService.saveData(objectToSave);
someService.printData (objects, priority);
}
I managed to make this, creating a service for managing the methods that will be fired.
angular.module('FTWApp').service('myService',function(){
var ac = this;
ac.addMethodForOnClose = addMethodForOnClose;
ac.arrMethods = [];
function addMethodForOnClose(idModule, method){
ac.arrMethods[idModule] = {
id: idModule,
method: method
}
};
function executeMethodsOnClose(){
for(object in ac.arrayMethods){
ac.arrMethods[object].method();
}
});
Then in the controllers, just add the method needed to that array:
myService.addMethodForOnClose(id, vm.methodToLaunchOnClose);
Afterwards, capture the $window.onunload and run myService.executeMethodsOnClose()
So I have a directive that takes in data objects as an argument into the scope. The problem is that I handle all my data in my service layer.
So this is some normal non-directive code:
angular.module('app').factory('appFactory', ['appValues', function(appValues) {
var getStuff = function() { return appValues.stuff; };
}]);
But if want to reuse the factory inside a directive and get appValues as an argument:
angular.module('app').directive('myDir', [function() {
return {
...
scope: {
values: '='
}
....
};
}]);
But this puts it on the scope and not into my data layer. So now I need to send the values object to every function call in my directive factory:
angular.module('app').factory('myDirFactory', [function() {
var getStuff = function(values) { return values.stuff; };
}]);
Is there any good pattern to solve this and keep data in the data-layer and bypass the scope/controller?
Also, the factory will be a singleton shared amongst instances of the directive? How should I solve that then? Create a new injector somehow? Submit to putting lots of data object logic into the controller (which I've been thought not to do)?
It was a while ago, and I guess that a simple soultion is simply to provide an function initialize(value) {... return {...};} and then the returned object has access to the value argument without providing it as a parameter everywhere:
angular.module('myDir').factory('myDirFactory', [function() {
var initialize = function(values) {
var getStuff = function() {
return values;
};
return {
getStuff: getstuff;
};
};
return {
initialize: initialize
};
}]);
I know that angular services are singeltons but I have an application in which I want that each directive instance will have a different service object which will hold context. How can it be achived?
You can use a factory that returns the constructor the class that you need, later just inject it to the controller and instantiate it.
app.factory('demoClass', function() {
return {
sayHello : function() { console.log('hello') }
}
});
At controller:
function myController($scope, demoClass)
{
var test = new demoClass();
test.sayHello();
}
Is it possible to instantiate a controller in AngularJS and pass arguments to its constructor like in OOP ? I can't figure out how to refactor 3 identical controller with just variables name and content which change...
Thanx.
If you have 3 separate sections on the page that have very similar controller code, it sounds like you should consider using a directive. Even if you don't need to control the DOM directly (which is the classic reason to use directive), and only need the standard Angular data-bindings, then this is a nice way to reuse controllers in different contexts by the attributes set on the directive.
You can see a working plunkr at
http://plnkr.co/edit/qclp6MOxGWP7Ughod4T8?p=preview
But the key point is directives can bind-to variables in their parent scope's controller. Say, in the parent scope you have 3 variables, so:
$scope.myVariable1 = 'Value 1';
$scope.myVariable2 = 'Value 2';
$scope.myVariable3 = 'Value 3';
Then you can setup 3 instances of the directive in the template:
<my-directive my-param="myVariable1"></my-directive>
<my-directive my-param="myVariable2"></my-directive>
<my-directive my-param="myVariable3"></my-directive>
Then each directive can use the variable in the 'my-param' attribute
scope: {
'myParam':'='
}
The '=' means that in the scope of the directive you have a variable, called 'myParam', that is equal (+ bound to) the variable specified by the 'my-param' attribute on the directive. So on the template of the directive, you can use:
<div>Value of parameter: {{myParam}}</div>
And in the controller of the directive, you have access to is as:
$scope.myParam
And should then be able to customise its behaviour based on that instance's myParam.
You can create services with a common interface and then pass the corresponding services to each controller through dependency injection. In my code this is the case of table controllers where the only thing that changes is the data source:
Imagine you have some code that looks like this
angular.module('myapp').controller('TableACtrl', ['$scope', function($scope) {
$scope.data = // get the data from some source
$scope.someFunction = function () { ... };
$scope.someOtherFunction = function () { ... };
}]);
angular.module('myapp').controller('TableBCtrl', ['$scope', function($scope) {
$scope.data = // get the data from some other source
$scope.someFunction = function () { ... };
$scope.someOtherFunction = function () { ... };
}]);
It looks something like:
var tableCtrl = function($scope, dataSource) {
$scope.data = dataSource.getData();
$scope.someFunction = function () { ... };
$scope.someOtherFunction = function () { ... };
};
angular.module('myapp')
.controller('TableACtrl', ['$scope', 'dataSourceA', tableCtrl])
.controller('TableBCtrl', ['$scope', 'dataSourceB', tableCtrl])
angular.module('myapp')
.service('dataSourceA', function() {
return {
getData: function() { ... }
};
});
angular.module('myapp')
.service('dataSourceB', function() {
return {
getData: function() { ... }
};
});
I would still put things within a module, so you don't pollute the global window. But that's a different issue.
What is the most simple way to share a method between 2 directives?
I've tried using a factory and injecting that in my directives. But then I can't pass parameters to the factory. So I can get data back from my factory but I can't make the factory dynamic.
.directive('myFirstDirective', [...])
.directive('seconDirective', [...])
.factory('MenuItems', [function(){
return "testString";
}]);
By adding the factory to my code I can do in any directive:
var test = MenuItems;
But what I wan't to do is:
var test = MenuItems(myParameter); //so I can change the return in menuItems depending on myParameter
You can use a service to do that:
https://gist.github.com/anonymous/50b659c72249b58c31bf
.factory('MenuItemsService', [function(){
return {
getMenuItems : function(parameter){
if ( parameter === 'foo' ){
return ['bar', 'jar', 'tar'];
} else {
return ['asd', 'bsd', 'csd'];
}
}
};
}]);
Then in each directive you can inject the service, e.g:
MenuItemsService.getMenuItems('foo');
MenuItemsService.getMenuItems('bar');
To share data creating a service is the right thing to do.
Create a function on your service to process the data
.factory('MenuItems', function(){
var someDataToShare = ...
return {
someFunction: function(data) {
// process data here
return someDataToShare
}
}
});
call it like this:
$scope.processedData = MenuItems.someFunction($scope.someData)