Often it is necessary to work with primitive lists, therefore, in order not to write the same methods, I collected them in one service. I will talk a little about it as an example of removing functionality from controllers.
Demo ,
sandbox (many are played with the demo, so the data can skip)
As you can see from the example, we have a problem: a bunch of lists with similar functionality (adding, deleting, sorting elements - what else could the lists have :-).
')
Service
Describing the same methods in controllers is clearly not the best idea. Fortunately, Angulyar offers several ways to make a common code using services. Read more about them
here .
For our task, the most simple type is used: factory:
angular.module('oi.list', []) .factory('oiList', function () { return function (scope, Resource) { scope.items = Resource.query() scope.add = Resource.add() ... } }
Now, introducing our service into the controller, we get a function that writes all the necessary methods into scope.
.controller('MyCtrl', ['$scope', 'ListRes', function ($scope, ListRes) { oiList($scope, ListRes); }])
Caching
Good, but you can still improve. When data is received by the Ajax ($ resource, $ http) Angular is by default caching the received data. This means, for example, that by loading a data page into the ng-view, leaving it and returning again will not have to load the data again, since they are taken from the cache.
Unfortunately, this only works in elementary cases. Angulyar caches requests, but not model. Those. loading and caching an array of data using
Resource.query()
, Angulyar will not take the data from the cache if you request it for an individual item using
resArr[0].get()
, because the request will be different. Since the cache is not related to the model in any way, updating it when the model is updated becomes a non-trivial task.
To solve these problems, add the
value
oiListCache
service to the application. The link to the model will be stored in it. If when loading data we see that the link is empty, we download from the server, otherwise we take the model by reference.
.value('oiListCache', {cacheRes: {}}) .factory('oiList', ['oiListCache', function (oiListCache) { return function (scope, cache, Resource) { if (angular.equals(oiListCache.cacheRes[cache], [])) {
For each model, we use the
cache
line that characterizes it, so that different models have a separate cache.
Methods
Inside the module are a bunch of functions for working with lists. I have such a set, you may be somewhat different. I will dwell a bit on the method that everyone will have: adding a new element. The easiest way is to show an item to the user when it is already added to the database and its ID is known. The downside is that the user will have to wait for a response from the server.
The best way is to show the new element immediately, and attach it to the database after receiving the reply. And here lies the big catch. What to do if the user deleted an item that does not have an ID yet? Or simultaneously added several elements? In this case, use the counter add / remove elements. When you send a request to add / remove the counter increases, when you receive a response decreases. I will not give the code, it is easy to find it in the
sandbox.Known Issues
I did not plan to make the module an open project, but since I put it in the article, I will mention the problems I know. Moreover, suddenly someone will advise something sensible.
- The parameters are the
Resource
object and the key for the cache cache
. If one could pull out his name from a resource, then it would have perfectly replaced the cache key. Unfortunately, I can not imagine how to get it.
- Each time the list is changed, the new location of the elements is sent to the server by the sort () function. The problem is that without
scope.$$phase || scope.$apply()
scope.$$phase || scope.$apply()
sending changes happens once.
- Now the model is recorded in the scope under the name scope.items, which can not be changed to another. I do not want to take out the name of a separate setting in the parameters I want to write
$scope.modelname = oiList($scope, 'list', ListRes)
in the controller, but the binding is broken, because when receiving data from the server, they are not directly assigned to the scope.