2013-04-18 3 views
6

Я пытаюсь внедрить 2 шаблонов в элемент и работать на них:AngularJS: несколько директив с включением на тот же элемент

<div 
    ic-first="foo" 
    ic-second="bar" 
    ic-third="baz" 
    ic-fourth="qux" 
> 
</div> 

icFirst следует вводить с помощью шаблона пустого DIV как ребенок его элемент. icSecond должен вводить второй DIV (с кучей контента) в качестве второго ребенка его элемента, поэтому результирующий HTML будет выглядеть следующим образом:

<div 
    ic-first="foo" // priority: 100 
    ic-second="bar" // priority: 50 
    ic-third="baz" // priority: 0 
    ic-fourth="qux" // priority: 0 
> 
    <div id="foo"></div> 
    <div> <!-- a bunch of stuff from the templateUrl --> </div> 
</div> 

Оба icFirst и icSecond будут инъекционные другие элементы во вновь созданные контейнеры.

Когда я определяю свойство шаблона директивы по обе директивы, я получаю сообщение об ошибке:

Error: Multiple directives [icFirst, icSecond] asking for template on: <div ic-first

Когда я добавляю transclude: true в обеих директив, icFirst выполняет просто отлично ... но тогда другие директивы на том же элемент не выполняется. Когда я устанавливаю transclude: 'element', другие директивы выполняют , но Я получаю сообщение об ошибке, что первый ребенок ($scope.firstObj) не определен.

Всех четыре директивы должны иметь доступ к охвату друг друга, так что я делаю большую часть своей работы в своих контроллерах:

app.directive('icFirst', ['ic.config', function (icConfig) { 
    return { 
    restrict: 'A', 
    priority: 100, 
    template: '<div id="{{firstId}}"></div>', 
    replace: false, 
    transclude: 'element', 
    controller: function icFirst($scope, $element, $attrs) { 
     // … 
     $scope.firstId = $scope.opts.fooId; 
     $scope.firstElm = $element.children()[0]; 
     $scope.firstObj = {}; // this is used by the other 3 directives 
    }, 
    link: function(scope, elm, attrs) { … } // <- event binding 
    } 
); 
app.directive('icSecond', ['ic.config', function (icConfig) { 
    return { 
    restrict: 'A', 
    priority: 0, 
    templateUrl: 'views/foo.html', 
    replace: false, 
    transclude: 'element', 
    controller: function icSecond($scope, $element, $attrs) { 
     // … 
     $scope.secondElm = $element.children()[1]; 
     $scope.secondObj = new Bar($scope.firstObj); 
     //^is used by the remaining 2 directives & requires obj from icFirst 
    }, 
    link: function(scope, elm, attrs) { … } // <- event binding 
    } 
); 

Примечания я исправил поведение replace: false в соответствии с документированным поведением, как описано в запросе на растяжение #2433.

Я попытался создать экземпляр $scope.firstObj в контроллере и установить его в linkFn (надеясь, что завершение будет завершено к моменту выполнения linkFn), но я получаю ту же проблему. По-видимому, первый ребенок - это комментарий.

ответ

1

Единственная причина, я могу придумать, что объясняет метания этой ошибки в том, что команда AngularJS пытается избежать ненужных перезаписывает/DOM манипуляция:

Учитывая реальное поведение replace: false против документированного поведения, я думаю, Фактически фактическое является предполагаемым поведением. Если это так, то использование нескольких шаблонов/templateUrls для одного и того же элемента приведет к тому, что последующие шаблоны будут перезаписаны предыдущими.

Так как я уже изменил источник в соответствии с документированным поведением, как быстро исправить , я изменил источник снова (/src/ng/compile.js:700), чтобы удалить assertNoDuplicate чек (что соответствует angular.js:4624). Теперь я возвращаюсь следующие 2 объекта, и он работает, и я не могу найти какие-либо негативные последствия:

// directive icFirst 
return { 
    restrict: 'A', 
    priority: 100, 
    replace: false, 
    template: '<div id="{{firstId}}"></div>', 
    require: ["icFirst"], 
    controller: Controller, 
    link: postLink 
}; 
// directive icSecond 
return { 
    restrict: 'A', 
    require: ['icFirst'], 
    replace: false, 
    templateUrl: 'views/bar.html', 
    priority: 50, 
    controller: Controller, 
    link: postLink 
}; 

Если перманентным, чек должен, вероятно, будет
if (directive.templateUrl && directive.replace)
(и аналогичные для directive.template)

+2

Теперь есть более простой способ.Просто добавьте '$$ tlb: true' в свою директиву, и он обходит утверждение. –

+1

@JonathanRowny '$$' указывает, что '$$ tlb' является 'private' для API и не должен использоваться за пределами API, так как разработчики могут решить сломать его в любое время. –

Смежные вопросы