在 AngularJS 服务中处理数据绑定
Posted
技术标签:
【中文标题】在 AngularJS 服务中处理数据绑定【英文标题】:Handling data binding in AngularJS Services 【发布时间】:2013-01-09 17:53:51 【问题描述】:我试图弄清楚当我的数据存储在服务中时您如何正确处理绑定。
如果将服务放入 $scope 然后让模板直接绑定到其中,我可以让事情正常工作,但这似乎是一个非常糟糕的主意。
我基本上希望拥有它,以便我的视图/控制器能够轻松更改服务中的状态并将其反映在任何地方。
感觉我应该能够执行以下操作,但它不起作用 (http://jsfiddle.net/aidankane/AtRVD/1/)。
<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'];
【问题讨论】:
我看到您在哪里观看 $scope.drawing 进行更改,但您没有更改模型,而是更改了所选项目。你不应该为选定的项目更改放置一个处理程序,可能在一个指令中吗? 如何使用指令来做到这一点?我认为 ngSelect 指令基本上给了我我需要的行为。我对这个问题的理解是控制器和服务之间的移动才是问题所在——我现在有点困惑:) 你是对的,现在我看到了你更新的小提琴,我对你在尝试什么有了更好的了解。你没有困惑:) 【参考方案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>
【讨论】:
好的。我想,这让我走上了正确的道路。因此,我创建了一个新版本 - jsfiddle.net/aidankane/EBr53 - 并且我在两个方向上创建了观察者以在服务之间推/拉。这是正确的做法吗? @AidanKane 是的!组件间通信是这里和邮件列表中的一个常见问题。服务是迄今为止最常见(通常也是更“正确”)的解决方案。 我很早就看到它们是保存数据的正确方式。只是在服务/控制器/视图之间的协调方面有点挣扎。似乎通过使用该服务,我必须在控制器中放置一些样板来同步事物(控制器中的东西太少了,我不介意)。感谢您的及时回复,不胜感激。 @mariachimike 通常有,但这在很大程度上取决于上下文。例如,您可以只做$scope.drawing = myService.drawing
并完全避开手表,但从关注点分离的角度来看,这通常是不受欢迎的。如果你有一个例子,我相信我们可以找到一些不那么通用和不那么冗长的东西。
@mariachimike 没错,但总有例外。【参考方案2】:
我认为,更优雅的是使用 Promise(参见 $q.deferred()
)并异步解决它们。然后在 promise 函数中,您可以将数据分配给 $scope
的成员。
【讨论】:
如果您只加载一次数据就可以了,但我认为正在更改的数据不会以 OP 正在寻找的方式自动绑定。可能是错的。【参考方案3】:有两种方法可以绑定来自服务的数据:1) 通过值(需要一个如上所述的观察者来检查对服务原始值的变量更改)2) 通过引用(值直接链接),这是我首选的数据绑定方法。
我将只解释第二种可能性,因为接受的答案已经显示了如何实现观察者。 This blog describes what I am going to explain very well.
I created this plunk to illustrate data binding by reference.
这是来自 plunk 的代码:
HTML
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script data-require="angularjs@1.5.0" 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>
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变量只是服务变量的一个拷贝,服务变量不再与服务变量有任何关系,不会改变当服务变量发生时。
当$scope var 设置为等于and 对象时,它由Reference 赋值。这意味着当服务对象(请注意,服务是一个对象,因为它是使用 new 关键字实例化的,并且您可以在服务内部使用“this”来引用该对象)或服务上被引用的任何对象发生更改时,任何引用这些对象的 $scope 变量也会更新。
【讨论】:
以上是关于在 AngularJS 服务中处理数据绑定的主要内容,如果未能解决你的问题,请参考以下文章