ng-model无法正确更新

时间:2014-07-03 12:18:24

标签: javascript angularjs angularjs-ng-repeat angular-ngmodel

我有这样的结构(非常简化):

<div ng-controller="MainCtrl">
  <div>Views and other stuff</div>
    <div ng-controller="MyCtrl">
      <div ng-repeat="item in $root.items track by $index">
        {{item.id}}
      </div>
    <div>
        Total value: {{totVal}}
    </div>
  </div>
</div>

在我的主控制器中,我定义了$ rootScope.items = [{id:1,..},{id:2,..},{id:3,..},..]和我的其他控制器我定义了$ scope.totVal = 0和items数组的观察器,当items数组更改时更新了totVal;

.controller('MainCtrl', ['$rootScope', '$scope', function($rootScope, $scope) {
    // Are actually fetched from a service
    $rootScope.items = [
        {id: 1,..},
        {id: 2,..},
        ..
    ];
}])

.controller('MyCtrl', ['$rootScope', '$scope', function($rootScope, $scope) {
    $rootScope.updateTotVal = function() {
        var totVal = 0;
        // calculations are done here
        // Is correct here when I console log after all calculations are complete
        console.log(totVal); 
        $scope.totVal = totVal;
    }

    $scope.totVal = 0;

    $rootScope.$watch('items', function() {
        $rootScope.updateTotVal();
    }, true);
}]);

我遇到的问题是totVal在视图中没有更新。当我控制台记录它在控制台中正确显示的值时,如果我将totVal div滚出视图并再次返回,它只会在视图中更新。看起来像是Chrome中的AngularJS错误,但在Google上找不到任何类似的情况。它在FireFox中运行良好。

如果我在ng-repeat之前移动totVal它可以工作,如果我删除了ng-repeat它可以工作(我宁愿不改变html的结构,因为它会有很多工作并且会使设计变得更糟)。我也尝试将totVal移动到根范围而没有任何成功。

只有绘画/渲染失败,Batarang和console.log总是给我更新的值。

以前有没有人遇到这个问题?

3 个答案:

答案 0 :(得分:1)

我不知道这是否正是您所寻找的,因为我不知道您的用例。 但是,我实现了一个工作示例,请在此处查看codepen

我重构了你的代码,删除了额外的控制器并在服务中封装了totVal。此外,我使用controllerAs语法使一切更清晰。

代码的问题在于totVal是一个原语。因此,当您为其指定新值时,angular将无法更新引用。这就是为什么你应该在模型中总是有一个点

看一下我的代码,你会认为totValvar totVal = {val : 0}。我只是更新val,保留引用并正确更新视图。

.service('totVal', function(){
  var totVal = {val:0};

  this.computeTotVal = function(){
    //perform computations, I will just increment
    totVal.val++;
  }

  this.getTotVal = function() { return totVal; }
})

另见article

答案 1 :(得分:0)

我不确定这是否是罪魁祸首,但你绝对不应该使用$rootScope

正如文件所述:

  

$ rootScope存在,但它可以用于邪恶

见这里:https://docs.angularjs.org/misc/faq#-rootscope-exists-but-it-can-be-used-for-evil


如果没有必要,我会在没有它的情况下重写代码:

<div ng-controller="MainCtrl">
  <div>Views and other stuff</div>
  <div ng-controller="MyCtrl">
  <!-- You also had an $root.items that didn't match any element here -->
    <div ng-repeat="item in items track by $index">
      {{item.id}}
    </div>
    <div>
      Total value: {{totVal}}
    </div>
  </div>
</div>

在您的控制器中,您将绑定您的项目,如下所示:

.controller('MainCtrl', ['$scope', function($scope) {
    // Are actually fetched from a service
    $scope.items = [
        {id: 1,..},
        {id: 2,..},
        ..
    ];
}])
.controller('MyCtrl', ['$rootScope','$scope', function($rootScope, $scope) {
    $scope.updateTotVal = function() {
        var totVal = 0;

        // calculations

        console.log(totVal); // Is correct here

        $scope.totVal = totVal;
    }

    $scope.totVal = 0;

    // Here $rootScope makes sense
    $rootScope.$watch('items', function() {
        $scope.updateTotVal();
    }, true);
}]); 

修改
此外,每次实例化控制器时,都会设置$rootScope.totalVal = 0,最终将其重置 也许这就是你没有看到更新的原因?

答案 2 :(得分:0)

问题出在Angular和Chrome上。如果我删除了在totVal输出之前的ng-repeat,那么它是否有效。如果我将totVal放在DOM结构中或ng-repeat之前,它也有效。 我认为它与绑定的数量和DOM的复杂性有关,许多嵌套的DIV以某种方式打破了绑定。我还注意到,如果我有很多嵌套的引导类,比如&#39; row&#39;和&#39; col-xs-12&#39;它也打破了绑定。所以它似乎与浏览器渲染/绘制视图有关(因为滚动totVal并返回到视图更新了值)。

我从中学到的主要内容是使用更智能的指令并尝试简化DOM结构,特别是如果你使用bootstrap。

原件:

<div ng-controller="MainCtrl">
  <div>Views and other stuff</div>
  <div ng-controller="MyCtrl">
    <div ng-repeat="item in $root.items track by $index">
      {{item.id}}
    </div>
    <div>
      Total value: {{totVal}}
    </div>
  </div>
</div>

使其正常运行的不同更改:

<div ng-controller="MainCtrl">
  <div>Views and other stuff</div>
  <div ng-controller="MyCtrl">
    <div>
      Total value: {{totVal}}
    </div>
  </div>
</div>

<div ng-controller="MainCtrl">
  <div>Views and other stuff</div>
  <div ng-controller="MyCtrl">
    <div ng-repeat="item in $root.items track by $index">
      {{item.id}}
    </div>
  </div>
  <div>
    Total value: {{totVal}}
  </div>
</div>

<div ng-controller="MainCtrl">
  <div>Views and other stuff</div>
  <div ng-controller="MyCtrl">
    <div>
      Total value: {{totVal}}
    </div>
    <div ng-repeat="item in $root.items track by $index">
      {{item.id}}
    </div>
  </div>
</div>