У меня есть директива с изолированной областью (чтобы я мог повторно использовать директиву в других местах), и когда я использую эту директиву с ng-repeat
, она не работает.
Я прочитал всю документацию и ответы на Stack Overflow по этой теме и понимаю проблемы. Я считаю, что избежал всех обычных ошибок.
Итак, я понимаю, что мой код не работает из-за области, созданной ng-repeat
директивой. Моя собственная директива создает изолированную область и выполняет двустороннюю привязку данных к объекту в родительской области. Моя директива назначит новое значение объекта этой связанной переменной, и это отлично работает, когда моя директива используется без ng-repeat
(родительская переменная обновляется правильно). Однако с ng-repeat
присваиванием создается новая переменная вng-repeat
видимости, и родительская переменная не видит изменений. Все это, как и ожидалось, исходя из того, что я прочитал.
Я также читал, что когда есть несколько директив для данного элемента, создается только одна область. И что a priority
может быть установлен в каждой директиве, чтобы определить порядок, в котором директивы применяются; директивы сортируются по приоритету, а затем вызываются их функции компиляции (ищите приоритет слова на http://docs.angularjs.org/guide/directive ).
Поэтому я надеялся, что смогу использовать приоритет, чтобы убедиться, что моя директива запускается первой и заканчивается созданием изолированной области, а при ng-repeat
запуске она повторно использует изолированную область вместо создания области, которая прототипически наследуется от родительской области. В ng-repeat
документации указано, что эта директива работает с уровнем приоритета 1000
. Неясно, 1
является ли уровень приоритета более высоким или более низким. Когда я использовал уровень приоритета 1
в своей директиве, это не имело значения, поэтому я попытался 2000
. Но это усугубляет ситуацию: мои двусторонние привязки становятся, undefined
а моя директива ничего не отображает.
Я создал скрипку, чтобы показать свою проблему . Я закомментировал priority
настройку в своей директиве. У меня есть список объектов имени и вызванная директива, name-row
которая показывает поля имени и фамилии в объекте имени. При щелчке отображаемого имени я хочу, чтобы оно установило selected
переменную в основной области. Массив имен, selected
переменная передаются в name-row
директиву с помощью двусторонней привязки данных.
Я знаю, как заставить это работать, вызывая функции в основной области. Я также знаю, что если он selected
находится внутри другого объекта, и я привязываюсь к внешнему объекту, все будет работать. Но на данный момент меня эти решения не интересуют.
Вместо этого у меня есть следующие вопросы:
- Как мне предотвратить
ng-repeat
создание области, которая прототипически наследуется от родительской области, и вместо этого использовать мою область действия директивы? - Почему уровень приоритета
2000
в моей директиве не работает? - Можно ли с помощью Батаранга узнать, какой тип прицела используется?
scope: true
для вашей директивы. См. Также (если вы еще этого не сделали) stackoverflow.com/questions/14914213/. Кроме того, тот факт , что директива будет использоваться в нескольких местах, не означает, что мы должны автоматически использовать изолированную область.ng-repeat
. Я считаю ценной возможность сочетать отдельные директивы сng-repeat
. Продолжение следует ...ng-repeat
не должно быть области действия.ng-repeat
наличие области действия имеет смысл для типичного варианта использования, поэтому я не предлагаю ее менять. Вместо этого, как я прокомментировал в ответе Алекса Осборна, я думаю, что создам повторную директиву, основанную наng-repeat
том, что она не создает свою собственную область. Затем это можно использовать для повторения директив, которые имеют свои собственные области действия. Продолжение следует ...ng-repeat
ли настраиваемую директиву повторения без области действия. Я думаю, что для «вызывающего» это нормально, но для «вызываемого» (повторяющаяся директива) недопустимо знать, повторяется это или нет. Продолжение следует ...Ответы:
Хорошо, благодаря множеству приведенных выше комментариев я обнаружил путаницу. Во-первых, пара уточнений:
Вот пример того же кода, но с удаленной директивой:
Вот JSFiddle, демонстрирующий, что это не сработает. Вы получите те же результаты, что и в вашей директиве.
Почему не работает? Поскольку области видимости в AngularJS используют прототипное наследование. Значение
selected
в вашей родительской области является примитивным . В JavaScript это означает, что он будет перезаписан, когда дочерний элемент установит то же значение. В области видимости AngularJS есть золотое правило: значения модели всегда должны содержать.
в себе. То есть они никогда не должны быть примитивными. См. Этот SO-ответ для получения дополнительной информации.Вот изображение того, как изначально выглядят прицелы.
После щелчка по первому элементу области теперь выглядят следующим образом:
Обратите внимание, что новое
selected
свойство было создано в области ngRepeat. Область действия контроллера 003 не была изменена.Вы, наверное, догадались, что происходит, когда мы нажимаем на второй элемент:
Таким образом, ваша проблема на самом деле вообще не вызвана ngRepeat - она вызвана нарушением золотого правила в AngularJS. Чтобы исправить это, просто используйте свойство объекта:
Вот второй JSFiddle, показывающий, что это тоже работает.
Вот как изначально выглядят прицелы:
После нажатия на первый элемент:
Здесь, при желании, изменяется область действия контроллера.
Кроме того, чтобы доказать, что это все еще будет работать с вашей директивой с изолированной областью (потому что, опять же, это не имеет ничего общего с вашей проблемой), вот JSFiddle для этого тоже, представление должно отражать объект. Вы заметите, что единственное необходимое изменение заключалось в использовании объекта вместо примитива .
Первоначально объемы:
Области действия после нажатия на первый элемент:
В заключение: еще раз, ваша проблема не в области изолированности и не в том, как работает ngRepeat. Ваша проблема в том, что вы нарушаете правило, которое, как известно, ведет к этой самой проблеме. Модели в AngularJS всегда должны иметь расширение
.
.источник
.
золотое правило требуется только для областей видимости с прототипным наследованием. С изолированными областями видимости интересующие вас переменные определены вscope: {}
определении в директиве, и поэтому эти переменные будут существовать в области изолированной области с самого начала. Кроме того, они не маскируют родительские переменные, потому что изолирующая область не наследуется прототипом от родительской области. т.е. нет никакой "родительской" области для маскировки..
.Не пытаясь напрямую не отвечать на ваши вопросы, вместо этого взгляните на следующую скрипку:
http://jsfiddle.net/dVPLM/
Ключевым моментом является то, что вместо того, чтобы пытаться изменить обычное поведение Angular и изменить его, вы можете структурировать свою директиву для работы,
ng-repeat
а не пытаться ее переопределить.В вашем шаблоне:
В вашей директиве:
В ответ на ваши вопросы:
ng-repeat
создаст область действия, вам действительно не следует пытаться это изменить.источник
ng-repeat
. Может быть, когда он впервые написан, он никогда не используется сng-repeat
. И когда-нибудь в будущем он может привыкнутьng-repeat
, и в этот момент он должен просто работать без перезаписи. Надеюсь, что в будущем выпуске AngularJS это станет возможным.ng-repeat
или нет. Но похоже, что мне пришлось бы передать функцию в директиву, чтобы она могла изменять переменные в родительской области, вместо того, чтобы иметь возможность изменять двустороннюю привязку в собственной области директивы. Двусторонняя привязка и многоразовые директивы - две мои самые любимые вещи в AngularJS, и ониng-repeat
оказались ложкой дегтя. Может быть, я смогу написатьng-repeat
эквивалент, не создающий собственной области видимости.