问题

我有一个异步获取数据并将其提供给 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分配给symbolsOptions,因此,它($scope.symbols)被分配了undefined而不是对symbol对象的引用。您可以通过在尝试分配之前添加几个控制台语句来查看此情况。由于symbols对象尚不存在,因此您的$scope.symbols变量无法引用它。

这对于peoplecities来说不是问题,因为您是通过$scope.options对象访问它们的,该对象引用了Opt服务返回的Options对象。由于基本引用保持不变,因此您的ng-repeats可以看到peoplecities子对象的更改。

如果您确实想将Options.symbols分配给$scope.symbols,则可以通过监视$scope.options.symbols来完成:

$scope.$watch('options.symbols', function(value) {
    $scope.symbols = value;
});

在示例示例插件更新后编辑

修改后的窃听器仍然表现出相同的行为,因为初始化的peoplecitiessymbols已被$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/

10-13 01:38