我正在尝试在Angular中编写一个非常简单的3星评分系统,但是当使用对数组中项目的引用时,我遇到了指令范围的问题。
出于测试目的,我的标记看起来像这样:
<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
当点击行时,每个得分框都会正确更新,但当你单击行上方的星号(使用对数组中第二项的引用)时,它将更新行中的两个指令,但不会更新本身。
我需要使用该指令来处理引用,因为该项被传递到另一个指令以在模态窗口中使用(我的应用程序与plunker具有相同的行为)。
提前感谢任何帮助。
答案 0 :(得分:0)
当您单击每行内的分数框时,两者都会正确更新,因为两个指令都在观看同一属性。因此,当其中一个指令更改启动次数时,另一个指令会通知该更改并强制执行渲染。由于两个指令都在同一ng-repeat
范围内,因此两个记分框都会重新呈现。
尝试从ng-repeat
内的行中删除其中一条指令,您会发现它将无法再正确更新。
解决此问题的一种方法是在设置视图值后调用ctrl.$render()
。像这样:
scope.set = function (score) {
if (ctrl.$viewValue === score) { score--; }
ctrl.$setViewValue(score);
ctrl.$render();
};
另一种选择是在ng-model
中定义scope
引用并直接更新。
require : 'ngModel',
scope: {
ngModel: '=?'
}
然后:
scope.set = function (score) {
scope.ngModel = score;
};