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);
};
};
});
Related
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', { ... });
Im going through one of the Pluralsight courses on AngularJS with MVC5 and one of the services has this as a return statement and it looks rather strange. Im not sure what this is doing
return {
insertEmployee: insertEmployee,
updateEmployee: updateEmployee,
getEmployee:getEmployee
};
the insert/update/get names are names of methods in the service, but I dont understand the return statement. What is this doing?
It returns an object with those methods available, example:
var methods = {
insertEmployee: insertEmployee,
updateEmployee: updateEmployee,
getEmployee:getEmployee
}
Now you can do:
methods.insertEmployee(); //etc...
Actually calling a service/factory (Both can be used the same way actually, despite the fact they're not intended to work the same way.) is just calling a function. The function you defined.
If you do this :
Service :
var myfunction = function(){
alert("hello");
}
Without any return you will not see this function in your controller.
Controller :
myservice.myfunction(); will not work.
You need to return an object to be able to use the functions.
Service :
var myfunction = function(){
alert("hello");
}
return {
myfunction: myfunction;
}
This will allow you to use the service this way in your controller :
myservice.myfunction();
I usually prefer to use the object syntax in an other way, but this is just a matter of tastes :
Service :
var service = {};
service.myfunction = function(){
alert("hello");
}
return service;
This will also allow you to use this syntax in the controller :
myservice.myfunction();
Hope it helped, if you have anymore question, feel free to ask.
Actually you can understand it as AngularJS defines a factory like that. It just means: I want to expose the functions insertEmployee, updateEmployee, and getEmployee to the users of this factory.
Please refer to AngularJS: Service vs provider vs factory.
In this way, say, your factory name is myFactory, the usage is like:
angular.module('MyApp')
.controller('MyCtrl', ['$scope', 'myFactory', function ($scope, myFactory) {
myFactory.getEmployee();
}]);
I have a directive which is associated with one controller and the functions in my controller defined as
MyFormController.prototype.addNewRow = function addNewRow() {
//Adding row code
};
I want to call this method from another controller, possible ways?
I ve user the service and moved the code into that service which is shared across the controllers, however the service code does the DOM manipulation, and then i guess the next question would be that can we use $compile in a service test case
service or factory is used to share data between controller.so it would be best to define function in service and factory.
demo:
(function() {
angular.module('app', [])
.service('svc', function() {
var svc = {};
svc.method = function() {
alert(1);
}
return svc;
})
.controller('ctrl', [
'$scope', 'svc', function($scope, svc) {
svc.method();
}
]);
})();
You should not!!!
That defeats the whole purpose of modularity.
If possible try to make the function generic and create a service/factory. Now both the places where you need, use the same generic function defined in service and do their stuff.
Otherwise you can also look at events to make changes accordingly.
Look at this blog post:
http://ilikekillnerds.com/2014/11/angularjs-call-controller-another-controller/
Last but the worst solution is (avoid using this, this is literally an aweful way) is catching the element inside directive and getting its scope and taking the function from it.
Example,
var otherControllerFunc = $(".inside-directive").scope().yourfunc;
I have a function that I will attach to my scope like this. It's attached to the scope as I use this function in my HTML pages Presently I am doing this in more than one controller. Note that my controllers are all top level controllers so I cannot really put this in a higher up controller and have it inherited.
$scope.isNotString = function (str) {
return (typeof str !== "string");
}
I asked how I could share this functionality and was given the following
example:
app.service('myService',function(){
this.sharedFunction = function() {
//do some stuff
};
});
myCntrl1($scope,myService) {
$scope.doSomething = function() {
myService.sharedFunction();
}
}
myCntrl2($scope,myService) {
$scope.doSomething = function() {
myService.sharedFunction();
}
}
Is there a way that I could more directly share it by passing
in $scope to the service and in that way eliminating the need for:
$scope.doSomething = function() {
myService.sharedFunction();
}
In each controller.
You can attach the function to the parent (root) scope, but using a service is the preferred way of sharing code between controllers.
You could call myService.init($scope) in the controller and that function could append properties to the scope but more likely you would want to use a parent controller from which you inherit.
You either declare a shared function in a top level "controller" or in a "service" like you mentioned in your example. There's no other better way so far.
You can assign the scope to a global variable, that will expose that scope globally, but will behave the same way like "service", except you don't have to inject it like service, rather can call by globalVar.dosomething().
I got services in angular that I need to be configurable, this way I can remove coupling from my app and share some of my code.
My question is how do you achieve this ?
With module.value() and dependancy injection ? Then how do you get a default value ? How do you make a value calculated at init and not hardcoded ?
With a another service ? How do you make that generic ?
Do you have a code exemple, because I'm a bit lost with this.
In order to create a configurable service, you need to use a provider, see: http://docs.angularjs.org/guide/providers. Providers allow you to configure the factory or service in the module's config block before it is instantiated. For a simple example, see http://plnkr.co/edit/QMLBBQ3obE90FtCA2eBu
For a more complete/complex example of how to use configurable services, I would suggest looking at the Restangular project, which also demonstrates a method of providing default values that can be overriden by the app developer.
I believe something like this should work within your service, if you were to use .value() to declare some objects for injection
var myLocalValue = myInjectedValue || "Some default value";
I'm not super javascript savvy but this answer on SO seems to elude to the fact that this will work too:
JavaScript OR (||) variable assignment explanation
I made a fiddle here to test it out it seems to work how I would expect:
http://jsfiddle.net/u3MY8/1/
JavaScript
var app = angular.module("myapp",[]);
// define a value
app.value('myThing', 'weee');
// use it in a service
app.factory('myService', ['myThing', function(myThing, myOtherThing){
var myLocalOtherThing = myOtherThing || "some default";
return {
whatsMyThing: function() {
return myThing; //weee
},
whatsMyOtherThing: function() {
return myOtherThing;
},
whatsMyOtherThingWithDefault: function() {
return myLocalOtherThing;
}
}
}]);
// use it in a controller
app.controller('someController', function($scope, myService) {
$scope.foo = myService.whatsMyThing(); //weee
$scope.bar = myService.whatsMyOtherThing(); //""
$scope.baz = myService.whatsMyOtherThingWithDefault(); //some default
});
HTML
<div ng-app="myapp" ng-controller="someController">
<ol>
<li>{{foo}}</li>
<li>{{bar}}</li>
<li>{{baz}}</li>
</ol>
</div>
To note this only works if myOtherThing isn't injected, if you list it to be injected but it hasn't been defined you'll run into errors, but I'm not sure exactly what the use case is.