Ответ 1
ОК, я думаю, что понял это
различное поведение ng-init
во внешних/внутренних els возникает из-за способа Angular выполняет свою фазу компиляции. компиляция состоит из разных этапов. наиболее важными в этом случае являются:
- создание экземпляра контроллера
- Предварительное связывание
- ссылки
- postlinking
которые выполняются в этом порядке на основе каждого DOM-кода (т.е. для каждого node, код контроллера, если он присутствует, выполняется перед любыми прелинками, ссылками или postlink f)
ng-init
регистрирует a pre
-link f на node, указанном, в котором $eval
содержание директивы (в моем примере f присваивает значение foo
prop). поэтому, когда выполняется код контроллера для того же node, prop еще не существует, что соответствует ответу @Aron
в фазе компиляции Angular пересекает DOM от корня вниз на основе глубины, что означает, что родительские элементы компилируются перед их дочерними элементами. поместив директиву ng-init
во внешний el, контроллер дочернего элемента node наследует внешнюю область. это объясняет "внешний el" взлом
hack @Aron указывает на регистрацию наблюдателя на опоре, так что, когда prop наконец-то $eval
uated в фазе prelink, обратный вызов f может найти его
Я предлагаю два других возможных хака на основе асинхронных функций JS и Angular (см. этот jsFiddle). один включает использование setTimeout
JS native f, тогда как другое больше Angular 'и прибегает к $evalAsync
imho, существует ошибка в реализации Angular директивы ng-init
в отношении объявленного намерения. Я взломал код Angular, чтобы поэкспериментировать с разнообразной реализацией. Это не сложно (добавлено 2 строки кода, даже до возможного удаления директивного кода директивы ng-init
), и работает, когда применяется к коду в jsFiddle выше, но я не тестировал его в сложных приложениях. Для тех, кто заинтересован, вот что я делаю (refs to v 1.2.0-rc2):
- в блоке
applyDirectivesToNode
f объявляю неинициализированныйnodeHasInitData
локальный var - в том же f, после локального
directiveName
var присваивается значениеdirective.name
prop, я проверяю его на статическую строку"ngInit"
, которая является нормированным именем Angular, присваивает директивеng-init
когда он объявлен на node - Если тест проходит, я устанавливаю
nodeHasInitData
вtrue
. ничего не делается, если тест не работает (- >nodeHasInitData
остаетсяundefined
в закрытии) - в блоке
nodeLinkFn
f, перед блокомif
, который проверяет наличие контроллеров в node (шаг 1 в списке выше), я добавляю тест на значениеnodeHasInitData
(Я могу это сделать, потому чтоnodeLinkFn
определяется внутриapplyDirectivesToNode
) - Если тест проходит, я вызываю
scope.$eval(attrs.ngInit)
, что и делает prelink f директивы nativeng-init
. обаscope
иattrs
являются собственными параметрамиnodeLinkFn
, поэтому они доступны. ничего не делается, если тест не работает. - таким образом, я переместил 1 инициализацию с шага 2 на новый шаг 0, который передает внутреннюю область el перед выполнением соответствующего кода контроллера.
<суб > 1. Фактически, я реплицировал его, потому что prelink f, определяемый директивой ng-init
, все еще существует. Однако это не очень много, и я думаю, что его можно было бы легко избежать, изменив/удалив объект директивы
ИЗМЕНИТЬ
Чтобы избежать репликации, безопасно для иллюстративных целей описанного выше хакера заменить код назначения ngInitDirective
Angular var на var ngInitDirective = valueFn({});