带有指令的AngularJs范围引用

时间:2014-09-04 10:58:32

标签: javascript angularjs

我正在尝试在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具有相同的行为)。

提前感谢任何帮助。

1 个答案:

答案 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;
};