在ng-repeat中嵌套Angular指令/子指令的内容传递

6

问题在于子指令绑定到父指令,但是{{name}}语法被ng-repeat忽略了。那么实现这个的正确方法是什么?

HTML(主/子指令)

<compact-select
    no-item-selected-text="Add a Customer"
    no-item-selected-icon="fa-user"
    search-placeholder="Type a customer name"
    cs-model="customer"
    cs-items="contacts"
>
    <display-item-template>
        <span>{{name}}</span>
        or
        <span>{{item.name}}</span>
    </display-item-template>
</compact-select>

指令

angular.module('core').directive('compactSelect', [function($timeout) {
    return {
        templateUrl : 'modules/core/views/components/compact-select-tpl.html',
        bindToController: true,
        transclude: true,
        scope: {
            noItemSelectedText: '@',
            noItemSelectedIcon: '@',
            csModel: '=',
            csItems: '=csItems'
        },
        controllerAs : 'ctrl',
        controller : function($scope) {

        }
    };
}]).directive('displayItemTemplate', function($timeout) {
    return {
        require: '^compactSelect',
        restrict: 'E'
    }
});

指令模板(modules/core/views/components/compact-select-tpl.html)

<div class="compact-select-repeater-box" style="" >
    <div ng-transclude ng-repeat="item in ctrl.csItems | filter:searchParam" class="compact-select-repeater" ng-class="ctrl.getHighlightedClass(item)" ng-click="ctrl.itemSelected(item)">
        <span>{{item.name}}</span>
        <span>{{item.id}}</span>
    </div>
    <div style="position:absolute;bottom:0">
        <a href="#">+ Click here to add customer {{ctrl.message}}</a>
    </div>
</div>

我能看到
<span>{{item.name}}</span>
<span>{{item.id}}</span>

被替换为

<span></span>
or
<span>{{item.name}}</span>

而不是使用

<span>{{name}}</span>
or
<span>{{item.name}}</span>

问题:如何让ng-repeat从子指令中获取html绑定语法?或者有其他方法可以实现这一点吗?

2个回答

9
如果我没理解错的话,您正在尝试创建一个列表视图,以便用户可以提供列表的模板,但是指令已经提供了方法(click等)。
自从Angular 1.3以来,传递范围(transcluded scope)是指令隔离范围(directive isolated scope)的子级。
因此,在您的情况下,如果按照正确的层次结构进行操作,您可以从用户提供的模板中访问指令作用域(directive scope)。
以下是您的作用域层次结构:
指令隔离范围 --> ng-repeat每行新的范围 --> 传递范围。
因此,如果您想从传递范围中访问指令范围,您需要使用 $parent(对于ng-repeat),然后像下面这样访问item.name:
<display-item-template>            
       <span>Item Name: {{$parent.item.name}}</span>            
</display-item-template>

此外,您不需要在compact-select-tpl中使用绑定,因为您希望该内容来自插槽传输。
<div class="compact-select-repeater-box" style="" >

    <div ng-transclude ng-repeat="item in ctrl.csItems | filter:searchParam" 
    class="compact-select-repeater" 
    ng-class="ctrl.getHighlightedClass(item)" 
    ng-click="ctrl.itemSelected(item)">
       <!--  <span>{{item.name}}</span>
        <span>{{item.id}}</span> -->
    </div>

    <div style="position:absolute;bottom:0">
        <a href="#">+ Click here to add customer {{ctrl.message}}</a>
    </div>
</div>

哇...这真是太棒了,运行良好。感谢您解释指令作用域生命周期。 - Tim

2
您需要将您想要插入另一个指令中的displayItemTemplate指令已经插值化的数据{{name}}{{item.name}}与之匹配。如果在$scope中没有这些变量,它将在您的中插入空字符串。
然后,在您的compactSelect指令中,被插入的div元素的内容将被覆盖。如果您将displayItemTemplate指令移动到另一个指令的模板中,则重复操作将起作用。(您需要删除ng(transclude和transclude:true)
此外,如果您使用bindToController,请不要将属性放在scope内。 Fiddle

function compactSelect() {
  return {
    template : [
      '<div class="compact-select-repeater-box" style="" >',
      '<div ng-repeat="item in ctrl.csItems | filter:searchParam" class="compact-select-repeater" ng-class="ctrl.getHighlightedClass(item)" ng-click="ctrl.itemSelected(item)">',
        '<display-item-template>',
            '<span>{{item.name}}</span>',
        '</display-item-template>',
      '</div>',
      '<div style="position:absolute;bottom:0">',
          '<a href="#">+ Click here to add customer {{ctrl.message}}</a></div></div>',
    ].join(''),
    bindToController: {
      noItemSelectedText: '@',
      noItemSelectedIcon: '@',
      csItems: '=csItems'
    },
    scope: {},
    controllerAs : 'ctrl',
    controller : function($scope) {

    }
  }
}
function displayItemTemplate() {
    return {
        require: '^compactSelect',
        restrict: 'E'
    }
}
function SuperController() {
 this.name = "a name";
 this.contacts = [{name:"rob"}, {name:"jules"}, {name:"blair"}];
}
angular.module('myApp', []);
angular
    .module('myApp')
    .controller('SuperController', SuperController)
    .directive('compactSelect', compactSelect)
    .directive('displayItemTemplate', displayItemTemplate);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<div ng-app="myApp">
  <div ng-controller="SuperController as s">
    <compact-select
        no-item-selected-text="Add a Customer"
        no-item-selected-icon="fa-user"
        search-placeholder="Type a customer name"
        cs-items="s.contacts">
    </compact-select>
  </div>
</div>


谢谢,我明白你的意思,但那不是我想要实现的。 - Tim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接