Можно ли использовать $$ prevSibling для доступа к данным области в директиве 'transcluded'?
Моя настройка директивы выглядит следующим образом:
<div data-directive-a data-value="#33ff33" data-checked="true">
<div data-directive-b></div>
</div>
- Я использую transclusion для обеспечения отображения
directiveB
.
-
directiveA
имеет флажок, который предназначен для изменения некоторого значения, когда он установлен.
- это значение должно быть доступно в области
directiveA
и directiveB
.
Мне удалось это сделать, но только путем ссылки $$prevSibling
- есть ли лучший способ?
Вот код: http://jsfiddle.net/janeklb/yugQf/ (в этом примере щелчок по флажку просто означает "очистить" значение)
-
Немного больше глубины:
"Содержимое" directiveA
(то, что переводится в него) не всегда directiveB
. Другие directiveB
-подобные директивы также окажутся там. Типы directiveB
"всегда будут использоваться в пределах directiveA
.
Ответы
Ответ 1
Чтобы избежать слишком сложного соединения компонентов, я бы не использовал $$prevSibling
. Лучшее решение, так как ваши компоненты directiveB
, как ожидается, будут использоваться в directiveA
компонентах, должны использовать require
.
.directive( 'directiveB', function () {
return {
require: '^directiveA',
scope: true,
link: function ( scope, element, attrs, directiveA ) {
scope.obj = directiveA.getObj();
}
};
})
^require
указывает, что где-то на элементе этой директивы или на любом элементе выше в иерархии DOM есть директива, называемая directiveA
, и мы хотим вызвать методы на ее контроллере.
.directive( 'directiveA', function () {
return {
// ...
controller: function ( $scope ) {
// ...
this.getObj = function () {
return $scope.obj;
};
}
};
})
Итак, теперь в directiveB
вы можете использовать ng-model="obj.attr"
.
В этом есть много вариаций, но, учитывая общий вопрос, я считаю, что это лучший подход. Здесь обновлен Fiddle: http://jsfiddle.net/yugQf/7/.
Ответ 2
@Джош упомянул в своем ответе, что
Лучшее решение, так как ваши компоненты directiveB
, как ожидается, будут использоваться в составе directiveA
, должны использовать require
.
Я играл с этим, и я считаю, что контроллер на directiveA
является единственным решением (так +1 Джош). Вот как выглядят области с помощью скрипта OP:
![scopes picture]()
(Переверните коричневую стрелку, и у вас есть $$ previousSibling вместо $$ nextSibling.)
Кроме $$previousSibling
, область 004 не имеет пути для выделения области 003. Обратите внимание, что область 004 представляет собой выделенную область, которую создает directiveA
, и поскольку directiveB
не создает новую область, эта область также используется на directiveB
.
Поскольку объект, который вы хотите использовать с directiveB
, создается в контроллере directiveA
, мы также не можем использовать атрибуты для обмена данными между директивами.
Создание модели внутри директивы, а затем разделение этой модели на внешний мир довольно нетипично. Как правило, вы хотите определить свои модели вне своих директив и даже вне своих контроллеров (прослушать несколько минут до Misko). Услуги часто являются хорошим местом для хранения ваших моделей/данных. Контроллеры должны обычно ссылаться на части модели (моделей), которые необходимо проецировать в представление, с которым они связаны.
Для простоты я собираюсь определить модель на контроллере, тогда директивы оба будут обращаться к этой модели обычным способом. Для педагогических целей directiveA
по-прежнему будет использовать область выделения, а directiveB
создаст новую область с помощью scope: new
, как в ответе @Josh. Но любой тип (изолировать, новый ребенок, новая область) и комбинация будут работать, теперь, когда у нас есть модель, определенная в родительской области.
Ctrl
$scope.model = {value: '#33ff33', checkedState = true};
HTML
<div ng-controller="NoTouchPrevSibling">
<div data-directive-a data-value="model.value" data-checked="model.checkedState">
<div data-directive-b></div>
</div>
По другим педагогическим причинам я решил передать директиву двух свойств модели в виде отдельных атрибутов, но также могла быть передана вся модель/объект. Поскольку directiveB создаст дочернюю область, ему не нужно передавать какие-либо атрибуты, так как он имеет доступ ко всем свойствам области родительского/контроллера.
директивы
app.directive('directiveA', function () {
return {
template: '<div>'
+ 'inside parent directive: {{checkedState}}'
+ '<input type="checkbox" ng-model="checkedState" />'
+ '<div ng-transclude></div>'
+ '</div>',
transclude: true,
replace: true,
scope: {
value: '=',
checkedState: '=checked'
},
};
});
app.directive('directiveB', function () {
return {
template: '<div>'
+ '<span>inside transcluded directive: {{model.checkedState}}</span>'
+ '<input type="text" ng-model="model.value" />'
+ '</div>',
replace: true,
scope: true
};
});
Прицелы
![scopes]()
Обратите внимание, что область childiveiveiveB (006) наследуется от директивы Transcluded scope (005).
После того, как вы установите флажок и измените значение в текстовом поле:
![scopes after interaction]()
Обратите внимание, что Angular обрабатывает обновление свойств области изоляции. Нормальное прототипное наследование JavaScript предоставляет доступ к объекту childiveiveiveB к model
в области контроллера (003).
Fiddle