Два способа привязки не работает в директиве с раскрываемый область
у меня есть текстовое поле в контроллере, который привязан к модели name
. Есть директива внутри контроллера и есть еще одно текстовое поле внутри директивы, которая привязана к той же модели name
:
<div class="border" ng-controller="editCtrl">
Controller: editCtrl <br/>
<input type="text" ng-model="name" />
<br/>
<tabs>
Directive: tabs <br/>
<input type="text" ng-model="name"/>
</tabs>
</div>
mod.directive('tabs', function() {
return {
restrict: 'E',
transclude: true,
template:
'<div class="border" ng-transclude></div>',
};
});
когда вы вводите что-то во внешнем текстовом поле, оно отражается во внутреннем текстовом поле, но если вы вводите что-то во внутреннем текстовом поле, оно перестает работать, т. е. оба текстовых поля больше не отражают одно и то же значение.
см. пример в: http://jsfiddle.net/uzairfarooq/MNBLd/
Я также пробовал использовать двухстороннюю привязку attr (scope: {name: '='}
), но это дает синтаксическую ошибку.И используя scope: {name: '@'}
имеет тот же эффект.
любая помощь была бы весьма признательна.
в дополнение к принятому ответу,в этой статье действительно помог мне в понимании прототипического наследования в детских scpoes. Я очень рекомендую всем, у кого есть проблемы с областями, чтобы прочитать его тщательно.
3 ответа:
директива с
transclude: true
приводит к директиве, создающей новую (закодированную) дочернюю область. Эта новая область прототипически наследуется от родительской области. В вашем случае родительская область-это область, связанная с контроллером editCtrl.использование двусторонней привязки данных в дочерней области (т. е. ng-model) для привязки к свойству родительской области, содержащему примитивное значение (например,
name
) всегда вызывает проблемы-ну, я должен сказать, что он не работает, как ожидалось. Когда свойство scope изменяется в дочернем элементе (например, вы вводите во второе текстовое поле) дочерний элемент создает новое свойство scope, которое скрывает/затеняет родительское свойство scope с тем же именем. Если родительское свойство содержит примитивное значение, то это значение (по существу) копируется в дочернее свойство при создании дочернего свойства. Будущие изменения в дочерней области (например, второе текстовое поле) влияют только на дочернее свойство.перед вводом во второе текстовое поле (т. е., прежде чем свойство будет изменено в дочернем элементе), дочерняя/закодированная область находит
name
свойство в родительской области через прототипное наследование (пунктирная линия на рисунке ниже). Вот почему два текстовых поля изначально остаются синхронизированными. Ниже, если вы введете "Mark" в первое текстовое поле, это то, как выглядят области:Я создал скрипка где вы можете изучить две области. Нажмите на ссылку "Показать область" рядом с второе текстовое поле перед вводом во второе текстовое поле. Это позволит вам увидеть трансцендентную дочернюю область. Вы заметите, что он не имеет
name
собственность на данный момент. Очистите консоль, введите во второе текстовое поле и снова щелкните ссылку. Вы заметите, что дочерняя область теперь имеетname
свойство, а начальным значением было значение, которое имело родительское свойство ("Mark"). Если вы набрали "likes Angular" во втором текстовом поле, это то, что выглядят области например:есть два решения:
- сделайте то, что предлагает @pgreen2 (это "лучшее решение") - используйте объект вместо примитива. При использовании объекта дочерняя / закодированная область не получает новое свойство. Здесь действует только прототипное наследование. На рисунке, приведенном ниже, предполагается, что $охвата editCtrl имеет этот объект определен:
$scope.myObject = { name: "Mark", anotherProp: ... }
:
- использовать $parent в дочерняя область (это хрупкое решение и не рекомендуется, поскольку оно делает предположения о структуре HTML): use
ng-model="$parent.name"
внутри , который находится в элементе. На первом рисунке выше показано, как это работает. синтаксическая ошибка возникает при использовании
scope: {name: '='}
потому что при использовании двусторонней привязки данных (т. е. при использовании'=') интерполяция не допускается-т. е. {{}} не может использоваться. Вместо<tabs name="{{name}}">
использовать<tabs name="name">
.С помощью '@' работает так же, как случай transclude, потому что ng-transclude использует область transcluded, а не изолированную область, созданную с помощью
scope: { ... }
.для получения (много) дополнительной информации об областях (включая фотографии) см.
каковы нюансы области прототипного / прототипического наследования в AngularJS?
Я считаю, что проблема связана с масштабированием. Изначально внутреннее текстовое поле не имеет
name
set, поэтому он наследуется от внешней области. Вот почему ввод текста во внешнем поле отражается во внутреннем поле. Однако после ввода во внутреннем поле происходит, внутренняя область теперь содержитname
Что означает, что он больше не привязан к внешнемуname
поэтому внешнее поле не синхронизировать.соответствующий способ исправить только хранение моделей в области, а не ваш ценности. Я исправил это в http://jsfiddle.net/pdgreen/5RVza/ фокус в том, чтобы создать объект модели (
data
) и ссылки на значения на нем.неправильный код изменяет область в директиве, правильный код изменяет модель в области в директиве. Это тонкое различие позволяет наследованию области работать должным образом.
Я считаю, что, как сказал Мишко Хевери, объем должен быть только для записи в контроллере, и только для чтения в директивах.
обновление: Ссылка:https://www.youtube.com/watch?v=ZhfUv0spHCY#t=29m19s