I have an angular component that is reused multiple time in the same page.
The angular component is dependent on a service, since it is reused multiple times, I would like to have a new instance of a service for each component, is that possible? Or do I have to use a for loop and create a separate object inside the service for each component to achieve the same effect?
Edit: I am using angular 1
You can create a factory (instead of a service) which returns a function to which you can even provide some data (think of it as a constructor).
angular
.module('app')
.factory('MyFactory', MyFactory);
function MyFactory() {
return (someOptions) => ({
myProperty: someOptions.myProperty,
myMethod: () => {
// ...
}
});
}
You can than use it in your controller like so. Every time you call MyFactory({ ... }) a new separate "instance" will be created.
angular
.module('app')
.controller('MyController', MyController);
function MyController(MyFactory) {
const myFactoryObj = MyFactory({ myProperty: 'test' });
}
You can use that service in each of your components as DI and then call that service to create a new instance every time. You can also set 'cache':true in your function so that you don't make multiple api calls for the same data. (Only for 'GET' method). Does that clarify your doubt?
Related
I have a controller (called searchCtrl) that does a request to a service and then inserts the data from that service into a scope called movieList.
I then display the content of the scope movieList through a ng-repeat in a template,
%li.search_results{"ng-repeat" => "movie in movieList'"}
.addmovie{"ng-click" => "addMovie()"}
%span
Add Movie
%span.title
{{ movie.original_title }}
In this template I call a function called addMovie() which creates a record in my database.
The issue here is that I want to seperate my search function and addMovie function in different controllers. That means that the addMovie() function is in a controller called addMovies.
So when I click on the .addmovie div and fire the addMovie() function, it doesn't do anything. So I'm wondering if it is possible to make a connection to the addMovie() function inside addMovies controller through the searchCtrl controller.
You need to move the addMovie() function into a service. That way any controller can access it just by injecting the service into the controller.
app.service("movieService",function() {
this.addMovie = function() {
//stuff
}
});
Then you would inject the service into your controller like this:
app.controller("searchCtrl",function($scope, movieService) {
//call it here
movieService.addMovie();
});
I am using angular and grafana in my project.
I have a service -> dashboardViewStateSrv
My Service Code :
define([
'angular',
'lodash',
'jquery',
],
function (angular, _, $) {
'use strict';
var module = angular.module('grafana.services');
module.factory('dashboardViewStateSrv', function($location, $timeout) {
function DashboardViewState($scope) {
var self = this;
self.state = {};
self.panelScopes = [];
self.$scope = $scope;
// something
}
return {
create: function($scope) {
return new DashboardViewState($scope);
}
};
});
});
In My side menu controller :
$scope.dashboardViewState = dashboardViewStateSrv.create($scope);
if ($scope.dashboardViewState) {
if($scope.dashboardViewState.state.citreedepth){
depth = +$scope.dashboardViewState.state.citreedepth;
}
}
In My Dashboard controller :
$scope.dashboardViewState = dashboardViewStateSrv.create($scope);
DashboardViewState object is being created twice (Dashboard Ctrl and Side Menu ctrl).
I am creating DashboardViewState object twice, I want to avoid that. If I can avoid creating DashboardViewState object in Side Menu ctrl?
There should be only one view state. As per my understanding all the services are singleton in angular.
Please guide me what I can do?
Services are singletons, they are essentially a constructure function allowing you to use the this keyword inside them. They are instantiated once when first created then that instance is shared throughout your app.
Factories are, well, factories. Somewhere in Angular it will call Object.create() on the object your return from a factory. Meaning each call will return a new instance of it.
So in your use case your creating a new object twice. First by using a factory, then second by returning a new object from that factory.
This may help http://blog.thoughtram.io/angular/2015/07/07/service-vs-factory-once-and-for-all.html
So if you want a single instance of an object through your application you should use .service() not .factory();
If you want to instantiate a new Object only once you could use a service. Have the object as a property and a get method. The service could check if the object is already created and if not make it.
something like this (example code, not tested):
module.service('dashboardViewStateSrv', function($location, $timeout) {
this.object;
this.get = function (){
if(this.object === undefined) {
return this.object = Object.create({}); //Create your object
} else {
return this.object;
}
}
});
however i did notice some booboo's (Sorry always reminds me of Hook when i say that). First you do not need to alias the this keyword, were not working in an jQuery callback, even if we were you can bind your function etc.
Second and this is important. Your passing a $scope object into your service, this is very very bad. Not just for this reason but how can controllers share a single service object if it has a reference to a $scope? Your services should be a collection of single simple methods that have their input and output data. They work on that and continue. You can then chain them and pass them the specific data each method needs. They shouldn't be a monolithic object that has everything in hidden properties, think functional, a pipeline if you will.
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 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 problem with bootstraping my angular application. I'm wondering, where should I place interface actions? Should I create special controller or maybe a service with these actions? For example: I want to create object responsible for showing alerts and call MyUiModule.showAlert(message) from any place within app.
Which approach is better - controller, service, something else?
As you want to use the showAlert functionality from any place within the app, the best place to put it is in service.
Now in any controller, where you want to avail this service, just inject it as dependency and call the method.
app.factory("MyUiModule", function() {
var UiModule = {};
UiModule.showAlert = function(message) {
// construct the interface to show the alert
// It could be angular-ui modal window
};
return UiModule;
});
In your controller where you want to use it:
app.controller("MyController", function($scope, MyUiModule) {
$scope.login = function() {
MyUiModule.showAlert("Please enter the username");
}
});