Обработка привязки данных в службах AngularJS
Я пытаюсь выяснить, как правильно обрабатывать привязку, когда мои данные хранятся в службе.
Я могу заставить все работать, если он помещает службу в область $scope, а затем заставляет шаблоны напрямую связываться с ней, но это кажется очень плохой идеей.
Мне бы хотелось, чтобы мои взгляды/контроллеры могли легко изменять состояние в службе и отражать ее везде.
Мне кажется, что я могу сделать что-то вроде следующего, но он не работает (http://jsfiddle.net/aidankane/AtRVD/1/).
HTML
<div ng-controller="MyCtl">
<select ng-model="drawing" ng-options="d.file for d in drawings"></select>
</div>
<div ng-controller="MyOtherCtl">
{{ drawing }}
</div>
JS
var myApp = angular.module('myApp', []);
myApp.factory('myService', function(){
var me = {
drawings: [{'file':'a'}, {'file':'b'}]
};
// selected drawing
me.drawing = me.drawings[0];
return me;
});
function MyCtl($scope, myService){
// can do:
// $scope.mys = myService;
// and then in html ng-model="mys.drawing"
// but that seems wrong
$scope.drawings = myService.drawings;
$scope.drawing = myService.drawing;
// can I not do this? it doesn't seem to work anyway...
$scope.$watch('drawing', function(drawing){
myService.drawing = drawing;
});
}
function MyOtherCtl($scope, myService){
$scope.drawing = myService.drawing;
}
MyCtl.$inject = ['$scope', 'myService'];
MyOtherCtl.$inject = ['$scope', 'myService'];
Ответы
Ответ 1
Вы можете привязываться к службам с помощью $watch
и передавать функцию:
$scope.$watch( function () { return myService.drawing; }, function ( drawing ) {
// handle it here. e.g.:
$scope.drawing = drawing;
});
И затем используйте $scope.drawing
в своих шаблонах, и они будут автоматически обновляться:
<div ng-controller="MyOtherCtl">
{{ drawing }}
</div>
Ответ 2
Я думаю, что еще более элегантно работать с promises (см. $q.deferred()
) и разрешать их асинхронно. В функции обещания вы можете назначить данные членам $scope
.
Ответ 3
Существует два способа привязки данных от службы: 1) По значению (для проверки изменений переменных для значения примитива службы требуется наблюдатель) 2) По ссылке (значения напрямую связанный), который является моим предпочтительным методом привязки данных.
Я объясню только вторую возможность, так как принятый ответ уже показывает, как наблюдатель может быть реализован. Этот блог описывает то, что я собираюсь объяснить очень хорошо.
Я создал этот plunk, чтобы проиллюстрировать привязку данных по ссылке.
Вот код из панели:
HTML
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script data-require="[email protected]" data-semver="1.5.0" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="myAppCntrl">
<h1>Hello Plunker!</h1>
<h3>By value</h3>
<p>{{byValue}}</p>
<p>{{objByValue}}</p>
<h3>By object in service reference</h3>
<p>{{byRefence.stringPrimitive}}</p>
<h3>By reference to service singleton</h3>
<p>{{myservice.stringPrimitive}}</p>
<p style="color: green">of course, you can reference an object through the service as well</p>
<p>{{myservice.objectWithPrimitive.stringPrimitive}}</p>
<button ng-click=update()>Update strings on service</button>
<br />
<button ng-click=setDefaults()>Restore Defaults</button>
</body>
</html>
JAVASCRIPT
var myApp = angular.module("myApp", []);
myApp.controller('myAppCntrl', function($scope, myAppService){
$scope.myservice = myAppService;
$scope.byValue = myAppService.stringPrimitive;
$scope.objByValue = myAppService.objectWithPrimitive.stringPrimitive;
$scope.byRefence = myAppService.objectWithPrimitive;
$scope.update = function () {
myAppService.stringPrimitive = "updated string";
myAppService.objectWithPrimitive.stringPrimitive = "updated string here too";
};
$scope.setDefaults = function () {
myAppService.stringPrimitive = 'string primitive';
myAppService.objectWithPrimitive.stringPrimitive = 'string primitive';
};
});
myApp.service('myAppService', function(){
this.stringPrimitive = 'string primitive';
this.objectWithPrimitive = {
stringPrimitive: 'string primitive'
};
});
Итак, как это работает?
Важно понимать, что это мало связано с тем, как работает angular, и многое зависит от того, как работает Javascript. Когда переменная устанавливается равным первообразному значению (или передается функции) в javascript (целое число, строка и т.д.) , var устанавливается значением. Это означает, что новая переменная является копией переменной, которую вы устанавливаете равной новому местоположению в памяти. Когда переменная устанавливается равным объекту (или передается функции) в javascript , var устанавливается по ссылке.
Что это значит?
Когда переменная $scope var задается по значению и изменяется служебная переменная, поскольку переменная $scope является только копией служебной переменной, служебная переменная больше не имеет ничего общего с служебной переменной и не изменится когда выполняется сервис var.
Когда параметр $scope var установлен равным и объекту, он присваивается ссылкой. Это означает, что когда объект службы (обратите внимание, что служба является объектом, поскольку она создается с помощью нового ключевого слова, и вы можете ссылаться на этот объект с помощью "this" внутри службы) или любые объекты в службе, на которые ссылаются, изменены, любая переменная $scope, которая ссылается на эти объекты, также будет обновлена.