Как указать angular, где отображать дочерние директивы внутри родительского шаблона (несколько включений)?

У меня проблема в том, что невозможно отобразить дочернюю директиву (selected-item-template) в родительском шаблоне.

Код ниже:

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>{{$parent.item.id}}</span>
        <span>{{$parent.item.name}}</span>
    </display-item-template>
    <selected-item-template>
       Your have selected customer: {{$parent.item.name}}
    </selected-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() {
    return {
        require: '^compactSelect',
        restrict: 'E'
    }
}).directive('selectedItemTemplate', function() {
    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>
    **HERE I WANT SELECTED ITEM TEMPLATE**
</div>

Вопрос: Как я могу определить, где должна отображаться дочерняя директива?

Директива на ng-repeat работает, но когда я добавляю две директивы, все объединяется вместе, а это не то, что я хочу. Есть ли способ указать с помощью ng-transclude, где отображать какую директиву? Как ng-transclude = "displayItemTemplate" и ng-transclude = "selectedItemTemplate" соответственно?


person Tim    schedule 21.06.2016    source источник
comment
вам нужно использовать $ compile, потому что вы хотите использовать multi директиву, см. эту статью, пожалуйста, Динамические директивы с использованием ng-repeat   -  person Maher    schedule 21.06.2016
comment
Спасибо, @Maher, пожалуйста, расскажите немного подробнее о том, как мне это сделать в моем примере?   -  person Tim    schedule 21.06.2016
comment
Я вам ответил, проверьте, пригодится ли что. :)   -  person Maher    schedule 21.06.2016


Ответы (2)


Этот пример основан на директивах, и я хочу показать вам, как несколько директив работают вместе в одном массиве.

Я надеюсь, это поможет вам.

    var app = angular.module("app", []);

        app.controller("ctrl", function ($scope) {

            $scope.selectedList = [];

            $scope.data = [
                { name: "a", checked: true },
                { name: "b", checked: false }
            ];

            $scope.getResult = function () {
                console.log($scope.selectedList);
            }

        });

        app.directive("directiveA", [function () {
            return {
                restrict: "E",
                template: "<ul ng-repeat=\"item in items\">" +
                    "<li><directive-c data=\"item\"></directive-c> {{item.name}} <directive-b data=\"item\"></directive-b></li>" +
                    "</ul>",
                scope: {
                    items: "="
                }
            };
        }]);

        app.directive("directiveB", function () {
            return {
                restrict: "E",
                template: "<button ng-click=\"renderData(data)\">{{data.checked ? 'unchecked':'checked'}}</button>",
                scope: {
                    data: "="
                },
                link: function (scope) {

                    scope.renderData = function (data) {
                        data.checked = !data.checked;
                    }

                }
            }
        });

        app.directive("directiveC", function () {
            return {
                restrict: "E",
                template: "<input type=\"checkbox\" ng-model=\"data.checked\">",
                scope: {
                    data: "="
                }
            }
        });

        app.directive("directiveD", function () {
            return {
                restrict: "E",
                template: "<ul ng-repeat=\"item in items\">" +
                    "<li ng-if=\"item.checked\">{{item.name}}</li>" +
                    "</ul>",
                scope: {
                    items: "=",
                    result: "="
                },
                link: function (scope) {

                    scope.$watch("items", function (newValue) {
                        scope.result = [];
                        if (newValue) {
                            angular.forEach(scope.items, function (item, index) {
                                if (item.checked) scope.result.push(item);
                            });
                        }
                    }, true);


                }
            }
        });
<!DOCTYPE html>
<html ng-app="app" ng-controller="ctrl">
<head>
    <title></title>
</head>
<body>

    <h3>items</h3>
  
    <directive-a items="data"></directive-a>

    <h3>selected items</h3>

    <directive-d items="data" result="selectedList"></directive-d>

    <hr />

    <button ng-click="getResult()">get selected list</button>
    <small>after click, check your console</small>

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

</body>
</html>

person Maher    schedule 21.06.2016
comment
спасибо @Maher, однако я узнал, как я могу получить несколько включений. - person Tim; 23.06.2016

Я понял, как добиться следующего. Это можно сделать с несколькими включениями, начиная с angular 1.5. Мне просто нужно определить transcludeSlot.

Код ниже:

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>{{$parent.item.id}}</span>
        <span>{{$parent.item.name}}</span>
    </display-item-template>
    <item-selected-template>
       Your have selected customer: {{$parent.csModel.name}}
    </item-selected-template>
</compact-select>

Директива

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

        }
    };
}]);

Шаблон директивы (modules / core / views / components / compact-select-tpl.html)

<div class="compact-select-repeater-box" style="" >
    <div ng-transclude="repeaterItemSlot" 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 ng-transclude="itemSelectedTemplateSlot"></div>
</div>

Так что это работает очень похоже на XAML.

person Tim    schedule 23.06.2016