范围的更改不会出现在子范围中

时间:2015-02-16 23:55:20

标签: javascript angularjs angularjs-directive angularjs-scope

我有一个指令pr-items使用模板和pr-item渲染子指令ng-repeat的实例:

app.directive('prItems', function(){
    console.log('prItems');
    return {
        restrict: 'E',
        scope: {
            items:'=',
        },
        template:'<pr-item ng-repeat="item in items"></pr-item>',
    ...
});

子指令pr-item使用另一个模板呈现内容:

app.directive('prItem', function($compile){
    console.log('prItem');
    return {
        restrict: 'E',
        template: '<div ng-style="{\'border-style\':item.border_style, \'color\':item.color}" style="cursor:pointer;"><span ng-if="item.selected">* </span>{{item.name}} {{item.selected}}</div>',
   ...
});

到目前为止一切正常。

单击该项目后,将通过$emit使用事件通知父指令。当父元素更改其中一个项目的状态时,此更改不会显示在相应项目中,如此Plunk中所示。

现在我很好奇我失踪了。

1 个答案:

答案 0 :(得分:1)

这是corrected Plunk

我试图记录我的更改(与您的版本相反)

app.directive('prItems', function(){
    console.log('prItems');
    return {
        restrict: 'E',
        scope: {
            items:'=',
        },
        template:'<pr-item ng-repeat="item in items"></pr-item>',
        link: function (scope, elem, attr) {
            console.log('prItems.link, scope.$id = ' + scope.$id);
            scope.$on('onSelecting', function (event, item) {
                console.log('prItems: onSelecting ' + item.name);
                //clear the selected flag for the other items
                angular.forEach(scope.items, function (value) {
                    if (value.selected) {
                        //console.log(value);
                        value.selected = false;
                    }
                });
                //set it for the item that was sent in
                item.selected = true;

                //change, no $scope.$apply - not needed here
            });
        }
    };
});

app.directive('prItem', function($compile){
    console.log('prItem');
    return {
        restrict: 'E',
        //ng-style will change camel case to - case borderStyle works (instead of using 'border-style' with escaped quotes.
        template: '<div ng-style="{borderStyle:item.border_style, \'color\':item.color}" style="cursor:pointer;">CLICK ME: <span ng-if="item.selected">* </span>{{item.name}} {{item.selected}}</div>',
        controller: function ($scope, $element) {
            console.log('prItem.controller, $scope.$id = ' + $scope.$id);
            //I left this in as-is, but there is a better way to do this by just using the template ($watch shouldn't be required)
            $scope.$watch('item.selected', function (val) {
                console.log('prItem.selected ' + $scope.item.name + ' changed to ' + val);
                $scope.item.border_style = val ? 'solid' : 'none';
                //console.log('$scope.item.border_style = ' + $scope.item.border_style);
            });
        },
        link: function (scope, elem, attr) {
            console.log('prItem.link ' + scope.item.name + ', scope.$id = ' + scope.$id);

              elem.on('mousedown touchdown', function () {
                //console.log('touché!');
                //scope.$apply should "wrap" non-angular code.  In the old version , you were calling scope.$apply() inline
                scope.$apply(function(){
                  scope.$emit('onSelecting', scope.item);
                  //instead of changing scope.selected, change item.selected - this change was probably not necessary
                  item.selected = !item.selected;
                });
                //old $scope.$apply();
              });
        }
    };
});

编辑:没有$ watch

app.directive('prItem', function($compile){
    console.log('prItem');
    return {
        restrict: 'E',
        //ng-style will change camel case to - case borderStyle works (instead of using 'border-style' with escaped quotes.
        template: '<div ng-style="{borderStyle:item.selected ? \'solid\' : \'none\', \'color\':item.color}" style="cursor:pointer;">CLICK ME: <span ng-if="item.selected">* </span>{{item.name}} {{item.selected}}</div>',
        controller: function ($scope, $element) {
            console.log('prItem.controller, $scope.$id = ' + $scope.$id);
        },
        link: function (scope, elem, attr) {
            console.log('prItem.link ' + scope.item.name + ', scope.$id = ' + scope.$id);

              elem.on('mousedown touchdown', function () {
                //console.log('touché!');
                //scope.$apply should "wrap" non-angular code.  In the old version , you were calling scope.$apply() inline
                scope.$apply(function(){
                  scope.$emit('onSelecting', scope.item);
                  //instead of changing scope.selected, change item.selected - this change was probably not necessary
                  item.selected = !item.selected;
                });
                //old $scope.$apply();
              });
        }
    };
});