-
Notifications
You must be signed in to change notification settings - Fork 0
Angular Services
Services are typically said to be a good idea because they modularize your code. But there's a more important reason to use services. $scope
shares data between controllers and templates. It doesn't share data between controllers. To share data between controllers you use a service. If you're having issues with child scopes and parent scopes, maybe you should be using a service.
Angular has five types of services:
- Value and Constant returns a value. They always return the same value.
- A factory receives a value, runs a function using the value, and returns a new value.
- A service creates a new function (using the
new
keyword). This is useful for object-oriented programming (OOP). -
Providers do the same things as the above services but with more verbose syntax, enabling more control, including using
.config
.
- Make a file for the service, starting with
app.value();
,app.factory();
etc. - Name the service, e.g.,
app.value('message');
. - Save the file in the
services
directory. Name it withmyValue.js
,myFactory.js
, etc. - Link from
index.html
to the service, e.g.,
<script type="text/javascript" src="javascript/services/myValue.js"></script>
<script type="text/javascript" src="javascript/services/myFactory.js"></script>
- Inject the service as a dependency into the controller, either
You inject the value as a dependency thus, and then call it:
app.controller("myController", ["$scope", "myValue", function ($scope, myValue) {
...
}];
Listing the dependency twice is done in case you intend to minimize your code. If you don't intend to minimize your code, save time and complexity:
app.controller("myController", function ($scope, myValue) {
...
};
- Now you can write your service.
The service is the second parameter. For a value it's just the value:
app.value("myValue", 9001);
app.value("myValue", "Hello world!");
myValue
is the name of the value. 9001
or Hello world!
is the value.
To call the value from the controller, use the name of the service:
$scope.powerValue = myValue;
The value can be an object:
app.value("myObject", {
animal: cat,
food: mice.
sound: purr
}
);
Then you can call properties:
$scope.myAnimal = myObject.animal;
The difference between values and constants has to do with configurations and decorators.
Factories are like values except that the second parameter is a function. The factory syntax is:
app.factory('myFactory', function() {
...
});
You can inject dependencies:
app.factory('myFactory', function(dependency, anotherDependency) {
...
});
But you can't inject $scope
into services. The purpose of a service is to pass data between controllers, and each controller has its own $scope
. Services have to be outside of all the scopes. Instead you use return
to pass data out of a service.
You can pass data into a factory through dependencies.
Our user story is that the user clicks a button in the view, which passes a value to the controller, which passes the value to a factory, which returns the value to the controller. We'll add logic to the factory later.
<button type="button" ng-click="some('ting')">Ting!</button>
app.factory('myFactory', function() {
console.log("My factory!") // logs early, when controller loads
let myData = null;
let fromController = function(data) { // 'ting' comes from first controller here
myData = data; // 'ting' transfers to the local variable
console.log(data); // ting, when user clicks button
};
let toController = function() {
return myData; // returns the local variable, which is now 'ting'
};
return { // this entire object is returned if the controller calls myFactory()
fromController: fromController, // this executes fromController and gets the data
toController: toController // this returns just the data if the controller uses dot notation to call myFactory.toController()
}
});
app.controller('MyController', function(sharingFactory) {
$scope.some = function(data) {
console.log(data); // ting
myFactory.fromController(data); // sends data to the factory, this could be a first controller
let ting = myFactory.toController(); // returns data from the factory, this could be a second controller; remember parentheses to execute the function
console.log(ting); // ting
}
};
The matching key: value pairs in the return enable you to call the functions in the factory from the controller. The keys are what you call in the controller, the values are the names of the functions in the factory,
Angular factories use "lazy instantiation." That means that a factory executes when it's injected as a dependency, not when it's called. This is why the console.log
executes when the factory loads as a dependency. Calling the factory makes your data pass through and return data:
app.factory("myFactory", function() {
console.log("Factory injected!");
return {
executeMyFactory: function() {
console.log("Factory executed!");
}
}
});
In the controller you then call the object:
console.log("This is just before the factory is called.")
authorizedUserFactory.queryGetRecord(); // call factory
console.log("This is just after the factory is called.")
You should then see:
This is just before the factory is called.
Factory called!
This is just after the factory is called.
A service can pass data between controllers.