问题
我有一个异步获取数据并将其提供给 Controller 的服务。在那里,它被附加到$scope
并在 View 中使用。
我不了解的是更新方面的差异,具体取决于 Controller 中此服务的使用方式。
例
该服务不是提供对数据的 promise ,而是公开数据本身。我在下面用超时对其进行了模拟:
(编辑:我已经将初始化添加到Opt
变量中,以表明这不能解决问题。)
app.service("Options", ["$q", "$timeout", function ($q, $timeout) {
var Opt = {
people:[],
symbols:[],
countries:[]
};
$timeout(function () {
Opt.people = [ {frst: "Johnny", last: "Walker"},
{frst: "Jack", last: "Daniels"},
{frst: "Jim", last: "Bean"} ];
}, 1000);
$timeout(function () {
Opt.symbols = [ {name: "Pi", descr: "circles"},
{name: "Phi", descr: "ratios"},
{name: "Psi", descr: "waves"},
{name: "Chi", descr: "distributions"} ];
}, 2000);
$timeout(function () {
Opt.cities = [ {name: "Amsterdam", country: "Netherlands"},
{name: "Cairo", country: "Egypt"},
{name: "Santiago", country: "Chile"} ];
}, 3000);
/* etc */
return Opt;
}]);
然后像这样在 Controller 中使用它:
app.controller("Ctrller", ["$scope", "Options", "$timeout", function ($scope, Options, $timeout) {
$scope.options = Options; //updating
$scope.symbols = $scope.options.symbols; //not updating
$scope.symbols = Options.symbols; //not updating either
$timeout(function(){
$scope.symbols = $scope.options.symbols; //updating
}, 4000);
}]);
我已经在Plnkr here中创建了一个现场演示。
如您所见, View 中的第二个
select
元素(以及$scope
的'symbol'属性)在4秒而不是2秒后更新。如果 Controller 中没有$timeout
,那么这当然不会发生。为什么会这样呢?为什么更改没有级联通过?
谢谢!
最佳答案
您尝试在$scope.symbols
服务返回的对象中存在$scope.options.symbols
数组之前,先将Options.symbols
分配给symbols
或Options
,因此,它($scope.symbols
)被分配了undefined
而不是对symbol对象的引用。您可以通过在尝试分配之前添加几个控制台语句来查看此情况。由于symbols
对象尚不存在,因此您的$scope.symbols
变量无法引用它。
这对于people
或cities
来说不是问题,因为您是通过$scope.options
对象访问它们的,该对象引用了Opt
服务返回的Options
对象。由于基本引用保持不变,因此您的ng-repeats
可以看到people
和cities
子对象的更改。
如果您确实想将Options.symbols
分配给$scope.symbols
,则可以通过监视$scope.options.symbols
来完成:
$scope.$watch('options.symbols', function(value) {
$scope.symbols = value;
});
在示例示例插件更新后编辑
修改后的窃听器仍然表现出相同的行为,因为初始化的
people
,cities
和symbols
已被$timeout
覆盖。如果要保持引用不变,则不得在=
中使用$timeout
运算符。一种选择是遍历返回的列表并通过推送添加每个项目:$timeout(function () {
results = [ {name: "Pi", descr: "circles"},
{name: "Phi", descr: "ratios"},
{name: "Psi", descr: "waves"},
{name: "Chi", descr: "distributions"} ];
angular.forEach(results, function(result) {
Opt.symbols.push(result);
});
}, 2000);
Here is a revised plunker with my suggested changes.
可能有更好的方法来完成此操作,但是关键是您不能将
Opt.symbols
重新分配给某些其他对象(即使该其他对象也是数组)。另一种方法是将
Opt.symbols
更改为其中具有数组的对象,您的引用$scope.symbols
指向该对象(Opt.symbols
)并可以查看内部值。Opt = {
people: [],
symbols: {},
cities: []
}
$timeout(function() {
Opt.symbols.values = [ {name: "Pi", descr: "circles"},
{name: "Phi", descr: "ratios"},
{name: "Psi", descr: "waves"},
{name: "Chi", descr: "distributions"} ];
}, 2000);
如果您走了那条路线,则需要调整ng-options使其看起来像,
ng-options="s as s.name for s in symbols.values"
Here is a working plunker of this approach.
除了我为之提供的两种示例之外,您还可以采用其他方法,这对于您的项目将是必须做出的决定。关键点在于,您不能在
$timeout
中重新分配Opt.symbols
的值,并且不能期望$scope.symbols
引用新值。关于javascript - $ scope选择性地更新服务解析,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26315732/