对指令的所有重复实例进行内部指令通信

时间:2013-08-29 21:41:17

标签: angularjs angularjs-directive

我试图在数据表中设置一个简单的突出显示机制:

<table>
    <thead>
        <tr>
            <th>Name</th>
            <th>Owner</th>
        </tr>
    </thead>
    <tbody>
        <tr ng-repeat="file in files" highlightable> <!-- Multiple instances of highlightable -->
            <td>{{file.name}}</td>
            <td>{{file.owner}}</td>
        </tr>
    </tbody>
</table>

我有一个处理突出显示的指令。您点击<tr>,它会尝试首先取消突出显示所有其他<tr>,然后突出显示所点击的directive('highlightable', function() { return { require: 'highlightable', controller: function($scope, $element) { this.unhighlight = function(file) { $element[0].style.backgroundColor = 'transparent'; }; }, link: function(scope, element, attrs, ctrl) { var color = '#DEE4FC'; element.bind('click', function(e) { ctrl.unhighlight(scope.file); element[0].style.backgroundColor = color; }); } }; });

ng-repeat

问题是它似乎没有访问指令控制器的每个实例。当需要另一个指令时,如何确保我在{{1}}场景中需要该指令的每个实例,并通过每个重复指令的控制器方法操作每个实例?

http://jsfiddle.net/txBJ6/1/

3 个答案:

答案 0 :(得分:1)

考虑到你想要实现的目标,我会这样做。基本上使用范围通知来在元素之间进行通信。

directive('highlightable', function() {
    return {
        link: function(scope, element, attrs) {
            var color = '#DEE4FC';
            scope.$on("reset", function() {
                element[0].style.backgroundColor = 'transparent';
            });
            element.bind('click', function(e) {
                scope.$parent.$broadcast("reset");
                element[0].style.backgroundColor = color;
            });
        }
    };
});

演示:link

<强>更新
sze正确地指出我的解决方案仅适用于您需要一个列表(从您的问题中看起来就是这种情况)。但是,在保持代码简洁的同时,很容易容纳多个列表。

<tr ng-repeat="file in files" highlightable="list1">
    <td>{{file.name}}</td>
    <td>{{file.owner}}</td>
</tr>

...

<tr ng-repeat="file in files" highlightable="list2">
    <td>{{file.name}}</td>
    <td>{{file.owner}}</td>
</tr>

...

directive('highlightable', function () {
    return {
        link: function (scope, element, attrs) {
            var color = '#DEE4FC';
            scope.$on(attrs.highlightable, function () {
                element[0].style.backgroundColor = 'transparent';
            });
            element.bind('click', function (e) {
                scope.$parent.$broadcast(attrs.highlightable);
                element[0].style.backgroundColor = color;
            });
        }
    };
});

演示:link

答案 1 :(得分:1)

[@buu Nyuyen]的应用问题是他错过了处理范围的一些逻辑。如果您有另一个由指令highlightable修改的列表,则如果从第一个列表广播该事件并使该指令不可重用,则第二个列表将受到影响。你可以在这里看到这个问题。 Issue

但是,您可以通过循环浏览其他元素轻松实现它。诀窍是你可以用element[0].parentElement.children获得所有重复的元素。

directive('highlightable', function () {
    return {
        require: 'highlightable',
        controller: function ($scope, $element) {
            this.unhighlight = function (element) {
                element.style.backgroundColor = 'transparent';
            };
        },
        link: function (scope, element, attrs, ctrl) {
            var color = '#DEE4FC';
            element.bind('click', function (e) {
                angular.forEach(element[0].parentElement.children, function (element) {
                    ctrl.unhighlight(element);
                })
                element[0].style.backgroundColor = color;
            });
        }
    };
});

Working Demo

答案 2 :(得分:0)

最简单的解决方案是Buu Nguyen提出的解决方案,我提供了一个更难的解决方案。

解决此问题的一种典型方法是拥有一个父指令,该指令将了解每个孩子。因此,您可以在每一行注册,当您点击一行时,父母将取消其他孩子的注意。

更复杂但更易于配置。您可以创建名为... multi的属性,以便能够突出显示多个属性。或者甚至可以选择最多x行......你想要什么。

如果你很好奇,我会在这里留下你的演示:http://jsfiddle.net/5NSW3/1/