AngularJS - 指令范围

时间:2013-12-10 01:59:04

标签: angularjs

我是AngularJS的新手。

有人可以解释为什么活动类不会在此代码中的标签之间切换:http://jsfiddle.net/eSe2y/1/

angular.module('myApp', [])
.filter('split', function () {
    return function (input, string) {
        var temp = string.split('|');
        for (var i in temp)
            input.push(temp[i]);
        return input;
    };
})
.directive('myTabs', function () {
    return {
        restrict: 'E',
        scope: { tabs: '@' },
        template:
            "<div>" +
                "<a ng-repeat='e in [] | split:tabs' ng-click='selectedIndex = $index' ng-class='{active:$index==selectedIndex}'>{{e}}</a>" +
            "</div>",
        replace: true
    }
});

如果我将ng-click表达式移动到控制器的方法,则代码按预期工作:http://jsfiddle.net/g36DY/1/

angular.module('myApp', [])
.filter('split', function () {
    return function (input, string) {
        var temp = string.split('|');
        for (var i in temp)
            input.push(temp[i]);
        return input;
    };
})
.directive('myTabs', function () {
    return {
        restrict: 'E',
        scope: { tabs: '@' },
        template:
            "<div>" +
                "<a ng-repeat='e in [] | split:tabs' ng-click='onSelect($index)' ng-class='{active:$index==selectedIndex}'>{{e}}</a>" +
            "</div>",
        replace: true,
        controller: ['$scope', function ($scope) {
            $scope.onSelect = function (index) {
                $scope.selectedIndex = index;
            }
        }]
    }
});

有人可以解释我的区别吗?以及如何修改第一个代码以使其工作而无需为控制器创建方法?

提前致谢。

1 个答案:

答案 0 :(得分:3)

问题解释

问题与javascript inheritance as it relates to scopes and directives in angular有关。基本上,当在子范围内时,从父级复制基本类型(int,boolean等)的所有属性。

在您的情况下,ng-repeat指令为每个元素创建子范围,因此每个链接都有自己的范围。在第一个示例中,selectedIndex仅在转发器中引用,每个转发器元素引用其自己的selectedIndex副本。您可以使用

进行调查

在第二个示例中,您在控制器中定义了一个selectedIndex对象,它是转发器的父作用域。因为selectedIndex属性在传递到控制器时最初是未定义的,所以它们会向父级查找定义。当此定义在onSelect方法中设置了值时,所有转发器元素都“看到”此值,并相应地更新。

如何调试

将来,您可以使用Angular Batarang调查这些类型问题。

  1. 浏览http://jsfiddle.net/eSe2y/1/show
  2. 左键单击其中一个标签
  3. 右键单击相同的链接
  4. 选择“检查元素”
  5. 打开调试控制台并键入$ scope.selectedIndex
  6. 为另一个标签重复上述步骤,并注意值的差异
  7. 现在转到调试器的元素选项卡,然后单击div
  8. 输入$ scope.selectedIndex并注意它未定义
  9. 在第二个小提琴上,尝试仅查看每个标签上的$scope(不是$scope.selectedIndex)。您将看到未在转发器元素上定义selectedIndex,因此它们默认为其父级的值。

    最佳做法

    避免此问题的典型角度最佳做法是始终引用可能在“点后”范围内更改的项目。这利用了JavaScript对象通过引用继承的事实,因此当属性在一个位置更改时,它会更改父子层次结构中的所有范围。我发布了一个更新的提琴手,通过简单地将绑定推送到对象上来解决问题:

    angular.module('myApp', [])
    .filter('split', function () {
        return function (input, string) {
            var temp = string.split('|');
            for (var i in temp)
                input.push(temp[i]);
            return input;
        };
    })
    .directive('myTabs', function () {
        return {
            restrict: 'E',
            scope: { tabs: '@' },
            template:
                "<div>" +
                "<a ng-repeat='e in [] | split:tabs' ng-click='s.selectedIndex = $index' ng-class='{active:$index==s.selectedIndex}'>{{e}}</a>" +
                "</div>",
            replace: true,
            controller: ['$scope', function ($scope) {
                $scope.s = {};
    
            }]
        }
    });
    

    http://jsfiddle.net/g36DY/2/