Search code examples
javascriptangularjsangularjs-directiveangularjs-ng-repeatangularjs-ng-transclude

Angular directive/child directive transclude inside ng-repeat


The problem is that child directive binds to parent however syntax {{name}} gets ignored by ng-repeat. What would be the right way achieving this?

HTML (Main/child directive)

<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>

Directive

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'
    }
});

Directive Template (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>

I can see that

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

Gets replaced with

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

and not with

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

Question: How do I get ng-repeat to respect html bindings syntax from child directive? Or is there is another way to achieve this?


Solution

  • If i am not wrong, then you are trying to create a list view such that the template of the list would be provided by the user, but the methods (click,etc) would already be made available through the directive.

    Now, since angular 1.3, the transcluded scope is a child of the directive isolated scope,

    so, in your case, if you follow the correct hierarchy, you can access the directive scope from within the template provided by the user.

    Here is your scope hierarchy:

    Directive isolated scope --> ng-repeat new scope for every row --> transcluded scope.

    so, if you want to access directive scope from the transcluded scope, you would need to do $parent (for ng-repeat) and then access item.name, like below:

    <display-item-template>            
           <span>Item Name: {{$parent.item.name}}</span>            
    </display-item-template>
    

    Also, you don't need the bindings inside your compact-select-tpl, because you want that content to come from transclusion:

    <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>