2014-09-04 57 views
2

我想在Angular中编写一个非常简单的3星评分系统,但是当使用对数组中的项目的引用时,我遇到了指令范围的问题。AngularJs范围参考与指令

为了测试我的标记看起来像这样:

<div id="ref"> 
    <span>Reference to item 1: </span> 
    <item-score ng-model="selected.score"></item-score> 
</div> 


<div ng-repeat="item in items track by $index"> 
    <div class="row"> 
     <span>{{item.name}}:</span> 
     <item-score ng-model="item.score"></item-score> 
     <item-score ng-model="item.score"></item-score> 
    </div> 
</div> 

而且我的JavaScript已被简化,但做同样的事情:

var App = angular.module('testApp', []); 

App.controller('MainCtrl', ['$scope', function ($scope) { 
    $scope.items = [ 
     { id: 1, score: 1, name: 'Item 1' }, 
     { id: 2, score: 2, name: 'Item 2' }, 
     { id: 3, score: 1, name: 'Item 3' } 
    ]; 
    $scope.selected = $scope.items[1]; 
}]); 

App.directive('itemScore', function() { 
    return { 
     restrict: 'E', 
     require: '?ngModel', 
     replace: true, 
     template: '<div class="score"><i class="fa fa-star" ng-click="set($index+1)"' + 
        ' ng-repeat="star in stars track by $index" ' + 
        'ng-class="{ yellow: star === true }"></i></div>', 
     link: function (scope, elm, attrs, ctrl) { 
      var num = 5; 

      scope.stars = new Array(num); 

      scope.set = function (score) { 
       if (ctrl.$viewValue === score) { score--; } 
       ctrl.$setViewValue(score); 
      }; 

      function setStars() { 
       for (var i = 0; i < num; i += 1) { 
        scope.stars[i] = ((i+1) <= ctrl.$viewValue ? true : false); 
       } 
      } 

      ctrl.$render = function() { 
       setStars(); 
      }; 
     } 
    } 
}); 

我创建了一个plunker http://plnkr.co/edit/QIXc1Nw68q7Zt1gsoa2P?p=preview

时点击行中的每个分数框都会正确更新,但是当你点击行上面的星号(使用对数组中第二项的引用)时, l更新行中的两个指令,但不会自行更新。

我需要该指令来处理一个引用,因为该项目被传递到另一个指令以在模态窗口内使用(我的应用程序具有与plunker相同的行为)。

任何帮助,将不胜感激提前。

+0

我认为你应该改变方法,你应该使用的方式结合指令,并以这种方式传递模型。 – bmazurek 2014-09-04 12:19:30

回答

0

当您单击每行内部的分数框时,两者都会正确更新,因为两个指令都在观察同一个属性。所以当其中一条指令改变了启动次数时,另一条指令会被通知这个改变并强制渲染。由于这两个指令都在相同的ng-repeat范围内,因此两个评分框都会重新呈现。

尝试从ng-repeat中的行中移除其中一个指令,您将注意到它将不再正确更新。

解决此问题的一种方法是在设置视图值后调用ctrl.$render()。就像这样:

scope.set = function (score) { 
    if (ctrl.$viewValue === score) { score--; } 
    ctrl.$setViewValue(score); 
    ctrl.$render(); 
}; 

另一种选择是定义在scope一个ng-model参考,并直接对其进行更新。

require : 'ngModel', 
scope: { 
    ngModel: '=?' 
} 

然后:

scope.set = function (score) { 
    scope.ngModel = score; 
}; 
+0

谢谢,这样一个简单的解决方案。在我们的主应用程序中调用$ render()似乎更可靠。 – 2014-09-04 13:28:47