Ответ 1
Директива с transclude: true
приводит к тому, что директива создает новую (трансключенную) дочернюю область. Эта новая область прототипа наследуется от родительской области. В вашем случае родительская область - это область, связанная с контроллером editCtrl.
Использование двухсторонней привязки данных в дочерней области (т.е. ng-model) для привязки к свойству родительской области, содержащему примитивное значение (например, name
), всегда вызывает проблемы - ну, я должен сказать, что это не работает должным образом. Когда свойство области изменяется в дочернем элементе (например, вы вводите во второе текстовое поле), дочерний элемент создает новое свойство scope, которое скрывает/тени свойство родительской области с тем же именем. Если родительское свойство содержит примитивное значение, это значение (по существу) копируется в дочернее свойство при создании дочернего свойства. Будущие изменения в области содержимого (например, во втором текстовом поле) влияют только на дочернее свойство.
Прежде чем вводить во второе текстовое поле (т.е. перед изменением свойства в дочернем элементе), область child/transcluded находит свойство name
в родительской области через прототипное наследование (пунктирная линия на рисунке ниже). Вот почему два текстовых поля изначально остаются в синхронизации. Ниже, если вы наберете "Марк" в первом текстовом поле, это выглядит так:
Я создал fiddle, где вы можете изучить две области. Нажмите ссылку "показать область" рядом со вторым текстовым полем, прежде чем вводить текст во второе текстовое поле. Это позволит вам увидеть трансключенный охват ребенка. Вы заметите, что на данный момент у него нет свойства name
. Очистите консоль, введите во второе текстовое поле и нажмите ссылку еще раз. Вы заметите, что дочерняя область теперь имеет свойство name
, а начальное значение - это значение, которое имеет родительское свойство ( "Mark" ). Если вы ввели "нравится Angular" во второе текстовое поле, это выглядит так:
Существует два решения:
- сделайте то, что предлагает @pgreen2 (это решение "лучшей практики" ) - используйте объект вместо примитива. Когда объект используется, область child/transcluded не получает новое свойство. Здесь используется только прототипное наследование. На рисунке ниже предположим, что область editCtrl $имеет этот объект:
$scope.myObject = { name: "Mark", anotherProp: ... }
: - используйте дочерний объект $parent в области содержимого (это хрупкое решение и не рекомендуется, поскольку оно делает предположения о структуре HTML): используйте
ng-model="$parent.name"
внутри <input> , который находится внутри элемента <tabs> . Первое изображение выше показывает, как это работает.
Синтаксическая ошибка возникает при использовании scope: {name: '='}
, потому что при использовании двусторонней привязки данных (т.е. при использовании '=') интерполяция недопустима, т.е. {{}} не может использоваться. Вместо <tabs name="{{name}}">
используйте <tabs name="name">
.
Использование '@' работает так же, как и для случая transclude, поскольку ng-transclude использует transcluded scope, а не область выделения, которая создается с помощью scope: { ... }
.
Для (лотов) больше информации о областям (включая картинки) см. Каковы нюансы объема прототипа/прототипического наследования в AngularJS?