如何修改指令中ng-repeat创建的每个元素的作用域

How to modify the individual scope of each element created by ng-repeat in a directive?

本文关键字:创建 作用域 元素 ng-repeat 何修改 修改 指令      更新时间:2023-09-26

我正在尝试写一个指令来简化Angular中的表。我只是想让用户提供列表对象和html中每个列表元素的格式的指令,像下面的my-table标签…

<h3>My Table</h3>
<div ng-controller='Ctrl as ctrl'>
<my-table items=ctrl.list>
    title: {{$item.title}}
    name: {{$item.name}}
</my-table>
</div> 

到目前为止,我已经得到了一些工作的答案,但我需要添加进一步的功能,我遇到了问题。在下面的my-table指令中,您可以看到link函数中的html模板。如何在每个列表元素的单独作用域中设置变量?当鼠标悬停在该元素上时,我应该能够修改它(使用ng-mouseenterng-mouseleave)?我应该能够将它传递给我在模板中引用的table-edit-panel指令…

(function() {
    'use strict';
    angular
        .module('myApp')
        .directive('myTable', myTable);
    myTable.$inject = ['$compile'];
    function myTable($compile) {
        var directive = {
            transclude: true,
            scope: {    
                items: '='            
            },
            link: link  
        };
        return directive;
        function link(scope, elem, attr, ctrl, transclude) {
            scope.onMouseLeave = function(testvar) {
                testvar.state = "ready";
            };
            scope.onMouseEnter = function(testvar) {        
                testvar.state = "active";           
            };
            // not working, seems to be only one testvar rather than one for each element
            var template = 
                '<div ng-repeat="$item in items" ng-mouseenter="onMouseEnter(testvar)" ng-mouseleave="onMouseLeave(testvar)">' +
                    '<div class="row">' +                   
                    '<div class="col-md-10">' +
                        '<placeholder></placeholder>' +
                    '</div>' + 
                    '<div class="col-md-2">' +
                        '<table-edit-panel value="testvar"></table-edit-panel>' +
                    '</div>' +
                    '</div><hr/>' +
                '</div>';               
            var templateEl = angular.element(template);
            transclude(scope, function(clonedContent){
                templateEl.find("placeholder").replaceWith(clonedContent);
                $compile(templateEl)(scope, function(clonedTemplate){
                    scope.testvar = { state: "ready" }; // should be a testvar for each element of the list!
                    elem.append(clonedTemplate);
                });
            });
        }
    }
})();

您可以访问jsfiddle上的完整代码。您可以看到问题是,使用我目前的方法,当我将鼠标悬停在一个列表元素上时,所有列表元素的testvar变量都会发生变化,而不是悬停在一个列表元素上。

使用$item.testvar代替testvar,您可以访问每个条目的子范围。

 var template = '<div ng-repeat="$item in items" ng-init="$item.testvar.state = ''ready''" ng-mouseenter="onMouseEnter($item.testvar)" ng-mouseleave="onMouseLeave($item.testvar)">' +
    '<div class="row">' +                   
    '<div class="col-md-10">' +
        '<placeholder></placeholder>' +
    '</div>' + 
    '<div class="col-md-2">' +
        '<table-edit-panel value="$item.testvar"></table-edit-panel>' +
    '</div>' +
    '</div><hr/>' +
'</div>';   

然而,在这个场景中需要初始化这些状态变量。我添加了一个ng-init来实现这一点。虽然这是ng-init的少数预期用途之一,但在我看来,在控制器中初始化状态变量更简洁。

更新(这次只使用作用域):

var template = 
    '<div ng-repeat="$item in items" ng-init="testvar.state = ''ready''" ng-mouseenter="onMouseEnter(testvar)" ng-mouseleave="onMouseLeave(testvar)">' +
    '<div class="row">' +                   
    '<div class="col-md-10">' +
        '<placeholder></placeholder>' +
    '</div>' + 
    '<div class="col-md-2">' +
        '<table-edit-panel value="testvar"></table-edit-panel>' +
    '</div>' +
    '</div><hr/>' +
'</div>'; 
var templateEl = angular.element(template);
    transclude(scope, function(clonedContent){
        templateEl.find("placeholder").replaceWith(clonedContent);
        $compile(templateEl)(scope, function(clonedTemplate){
            // REMOVED THIS LINE:
            // scope.testvar = { state: "ready" };
            elem.append(clonedTemplate);
        });
    });