Angular $scope更新、导航和 $scope.$apply() 后不绑定到视图



我有一个保存列表的数据库。我有一个表单,它通过factory向数据库列表添加一行。添加行后,服务器将发回更新的列表。使用$http.post返回的$q.defer().promise,我用defer.resolve更新的列表更新controller$scope上的列表。

在测试时,我遇到了异常情况。我的问题是,如果我离开具有执行更新controllerview并返回更新完成前的view,则当更新完成时,$scope不会使用更新的列表进行更新 - 好吧,无论如何它都不会在view中更新。如果我离开(在 SPA 内),然后再次返回,我会得到正确的数据。

执行更新的factory从其setData函数中的post返回promise。当承诺解析时,$scope将更新。

这是controller中的代码,耐心等待$http.post解析:

  promise.then(function() {
    $scope.people = dataService.getData();
    $scope.newperson = '';
    $scope.submitting = false;
    $scope.$apply();
  });

这是相应视图中的 html,它应该与 $scope.people 无缝绑定:

<li class="list-group-item" ng-repeat="person in people">{{person.firstName}} {{person.lastName}}</li>

我在这个JSBin中模仿了缓慢的服务器响应(使用setTimeout):https://jsbin.com/hihazegosi/1/edit?js,console,output

要重新创建问题:

  1. 导航到People
  2. 添加人员。在控制台中查看调用的帖子。
  3. 在 5 秒内导航到Home并返回People
  4. 等待人员,并在控制台中注意应已将人员添加到范围。
  5. 如果导航到Home并直接返回到People ,您将看到模型已更新。

请注意,如果您 a) 在帖子完成后导航回People,您将看到正确的数据。如果您 b) 留在People 上,您将看到正确的数据。 调用$scope.$apply()而不检查$scope.$$phase因为这在所有情况下都会返回'$digest',因此您将在方案 b 中看到错误。

谁能解释一下这里发生了什么,以及是否有办法让$scopeview在这种情况下保持同步?

我相信

正在发生的事情是这样的:

  • 当您离开人员状态时,控制器及其范围被破坏
  • 因此,当dataService.setData承诺解析时,它$scope不是指人员控制器的范围(它指的是您导航离开之前的旧控制器)
  • 然后,当您切换到主页并随后切换回人员时,将再次重新创建人员控制器,并且在其构造函数中执行dataService.getData然后用正确的值填充其$scope.people

我认为您需要将人员列表存储在状态更改中持续存在的某个地方,例如在dataService服务中

您还可以使用 $broadcast 在控制器需要更新时将消息传递给控制器。您可以像这样执行此操作:

  • dataService.setData解析时,执行$rootScope.$broadcast('peopleUpdated') - 这会将消息从根范围向下发送到应用中的所有范围
  • 使用$scope.$on('peopleUpdated', function() { $scope.people = dataService.getData(); })在控制器中侦听此事件

最新更新