Почему область ng-transclude не является дочерним элементом своей директивной области - если директива имеет изолированную область видимости?
Учитывая директиву (container1
) с transclude и изолированной областью действия, когда директива связана, я имею следующие области:
Scope 004 <-- scope of the body
Scope 005 <-- scope of directive container1
Scope 006 <-- scope of the ng-transclude
Я ожидал:
Scope 004 <-- scope of the body
Scope 005 <-- scope of the directive
Scope 006 <-- scope of the ng-transclude
Если одна и та же директива имеет общую область видимости вместо изолированной области видимости, я получаю ожидаемый результат.
Это вызывает у меня проблему, потому что, если транслируемый контент содержит другую директиву (component1
) с изолированной областью, я получаю:
Scope 004 <-- scope of the body
Scope 005 <-- scope of the directive
Scope 006 <-- scope of the ng-transclude
Scope 007 <-- scope of directive component1
Я хочу использовать такие директивы, как это:
<container1>
<component1 data="objectExposedInContainer1"/>
</container1>
Но это не работает, внутри component1
, $scope.data
есть undefined
, потому что objectExposedInContainer1
не находится в правильной области.
У меня есть два вопроса:
- Почему область
ng-transclude
не является дочерним элементом своей области директивы, если директива имеет изолированную область видимости? Это ошибка?
- Если это не ошибка, как директива контейнера может передавать данные в контент, если не путем установки таких атрибутов, как я пытался.
Вот пример, где он не работает: http://plnkr.co/edit/NDmJiRzTF9e5gw8Buht2?p=preview. Поскольку Plunker построен с Anguar, его трудно отлаживать с Batarang. Я рекомендую загрузить код локально. Комментируйте line 10
of app.js
, чтобы он работал с использованием общей области.
Ответы
Ответ 1
Почему область ng-transclude не является дочерним элементом своей области директивы, если директива имеет изолированную область видимости?
ng-transclude
, предназначенный для разрешения директив работать с произвольным контентом, а изолированные области предназначены для того, чтобы директивы могли инкапсулировать свои данные.
Если ng-transclude
не сохранил такие области видимости, любой произвольный контент, который вы переводите, должен знать сведения о реализации вашей директивы (т.е. он должен знать, что доступно в изолированной области, которую вы создали).
Если это не ошибка, как директива контейнера может передавать данные в контент, если не путем установки таких атрибутов, как я пытался.
Если директива контейнера и содержащиеся в нем директивы связаны друг с другом - т.е. вы написали оба из них и должны действовать вместе - тогда они должны взаимодействовать через общий контроллер.
Если директива контейнера должна вводить содержимое в область содержимого дочерних элементов (например, ng-repeat), тогда вы не должны использовать изолированную область.
Документация angular достаточно понятна для того, как должно выглядеть поведение:
"В типичной настройке виджет создает область изоляции, но переключение - это не ребенок, а родственник изолята. Эта позволяет виджету иметь личное состояние, а переход должен быть привязан к родительскому (предварительно изолированному) объему."
Ответ 2
вы можете вручную перенести дочерний элемент
link: function(scope, element, attrs, ctrl, transclude) {
transclude(scope, function(clone, scope) {
element.find('.transclude-placeholder').append(clone);
});
}
Ответ 3
Верхний ответ верен только для Angular до v1.2.
Так как Angular v1.3, поведение изменилось, и теперь оно ведет себя точно так, как описано в части "Я ожидал" вопроса, сделав этот вопрос устаревшим для Angular v1.3 +.
Источник: https://github.com/angular/angular.js/commit/fb0c77f0b66ed757a56af13f81b943419fdcbd7f