Не понимаю postlink в директиве angular

Привет всем, я пытаюсь заполучить "расширенный" DOM ​​моей директивы. То есть я хочу иметь возможность находить элементы DOM, которые генерируются этой директивой, и управлять ими. Я думал, что это должны были делать функции link или postlink, но я продолжаю находить нерасширенную версию моего шаблона (или, по крайней мере, то, что должно генерировать ng-repeat, отсутствует). Вот мой пример. Обратите внимание, что количество элементов «li» равно нулю в функциях до и после ссылки, но после тайм-аута их пять. Мне нужно найти пятерку, но без подвохов таймаута! Как правильно найти эту структуру, чтобы я мог с ней работать?

РЕДАКТИРОВАТЬ:

Хорошо, я полагаю, что я определил, что происходит то, что шаблон действительно был заменен в элемент (на самом деле, по-видимому, к тому времени, когда вызывается функция предварительной ссылки. Проблема в том, что она не была «оценена» (я думаю, этот этап - это то, что документы довольно странно называют «интерполированным») даже к моменту вызова функции пост-ссылки.

То есть, если я помещаю в тело моих функций pre, post и timeout ниже вызов для печати внутреннего html элемента, я получаю:

pre/post html is<ul><!-- ngRepeat: item in list --></ul>

но после тайм-аута появляется куча <li> элементов. Итак, вопрос действительно должен заключаться в том, «как мне получить обратный вызов после того, как шаблон был оценен / интерполирован?

(ИЗМЕНИТЬ снова, я изменил приведенный ниже пример кода, чтобы он соответствовал этому новому описанию!)

ИЗМЕНИТЬ снова, чтобы добавить предложенную $ compile (и использовать $ timeout). Я заметил, что это ничего не меняет. Я думаю, проблема не в компиляции как таковой, а в расширении ngRepeat, которое, кажется, каким-то образом происходит в другом «цикле».

<!doctype html>
<html data-ng-app="MyModule">

<body data-ng-controller="MyController">
    <h1>Version 3</h1>
    <test></test>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
    <script>
        angular.module('MyModule', [])
            .controller('MyController', function ($scope) {
                $scope.list = [1, 2, 3, 4, 5];
            })
            //.directive('test', function ($compile) {
            .directive('test', function ($compile, $timeout) {
                return {
                    template: '<ul><li ng-repeat=" item in list ">{{item}}</li></ul>',
                    compile: function compile(tElement, tAttrs, transclude) {
                        return {
                            pre: function preLink(scope, iElement, iAttrs, controller) {
                                //console.log('pre, li count is ' + iElement.find('li').length);
                                console.log('pre html is' + iElement.html()); 
                            },
                            post: function postLink(scope, iElement, iAttrs, controller) {
                                //console.log('post, li count is ' + iElement.find('li').length);
                                console.log('post html is' + iElement.html());
                                 iElement.append($compile(this.template)(scope));
                                console.log('post-compile html is' + iElement.html());

                                //setTimeout(() =>
                                $timeout(() => 
                                  console.log('post timeout, li count is ' 
                                    //+ tElement.find('li').length),
                                    + tElement.html()),

                                    10, true);
                            }
                        }
                    }
                };
            });
    </script>
</body>
</html>

ТИА, Тоби


person Toby Eggitt    schedule 18.06.2016    source источник
comment
Вот хороший пост на compile vs pre-link vs post-link, также link и post-link - это одно и то же, если вы просто укажете link, это неявно post-link   -  person Robin-Hoodie    schedule 18.06.2016
comment
вы используете предварительную компиляцию и последующую компиляцию, а не ссылку   -  person Petr Averyanov    schedule 18.06.2016
comment
Это правда, Петя, извините за непонятность. Я начал использовать ссылку, но получил тот же эффект. Я прочитал еще немного, попробовал компилировать / пре / пост, но не получил никаких изменений. Похоже, вы не можете использовать и компиляцию, и ссылку, поскольку ссылка игнорируется, поэтому мне пришлось сделать выбор для моей иллюстрации.   -  person Toby Eggitt    schedule 18.06.2016
comment
NexusDuck, спасибо за ресурс; пока мне не удалось определить, есть ли там мой ответ. Этой статьи (и ее последующих) много, и я не уверен, что вы занимаетесь хорошим преподаванием (то есть заставляете меня выполнять работу) или это просто еще один ресурс, который может помочь мне понять что-то в целом? Если вы сидите на более конкретном указателе с намерением позволить мне разобраться с этим, знайте, что я был бы благодарен за возможность быть немного более ленивым :)   -  person Toby Eggitt    schedule 18.06.2016
comment
не используйте setTimeout с angular, он не знает angular. используйте вместо этого $timeout. При этом в вашем случае вам, вероятно, следует использовать $compile для получения доступа к скомпилированному элементу, а не к функциям link. Результатом link функций является HTML, который будет добавлен к DOM; они - последнее место, где вы можете манипулировать HTML до того, как это повлияет на DOM, а не первое место, где вы можете получить доступ к измененному дереву DOM.   -  person Claies    schedule 18.06.2016
comment
обширную документацию по полному процессу компиляции можно найти на странице docs.angularjs.org/guide/compiler. В частности, раздел Как составляются директивы. // Шаг 1: разобрать HTML в элемент DOM ... // Шаг 2: скомпилировать шаблон ... // Шаг 3: связать скомпилированный шаблон с областью. ... // Шаг 4: Добавить в DOM (необязательно)   -  person Claies    schedule 18.06.2016
comment
Описание того, как работает директива ng-repeat, также должно быть поучительным; фаза компиляции, на которой все директивы идентифицируются и сортируются по приоритету, и фаза связывания, на которой выполняется любая работа, которая связывает конкретный экземпляр области и конкретный экземпляр <li>. ngRepeat работает, предотвращая спуск процесса компиляции в элемент <li>, чтобы он мог создать клон оригинала и самостоятельно обрабатывать вставку и удаление узлов DOM.   -  person Claies    schedule 18.06.2016
comment
Claies, спасибо за вклад. 1) Да, я знаю, что обманул setTimeout, это был хакер, чтобы доказать свою точку зрения, но хорошо, что вы назвали это здесь, чтобы другие не подумали, что это хорошая идея позже. 2) Это глубокое понимание, которое мне нужно построить, чтобы узнать, как получить обратный вызов после завершения ngRepeat (и я понимаю, что он может выполняться несколько раз по мере изменения DOM. мне конкретный указатель на то, как уловить этот обратный вызов? У меня большие трудности с объемом информации, который мне, кажется, нужно обработать, чтобы заставить эту работу работать.   -  person Toby Eggitt    schedule 18.06.2016
comment
Да, также, я пытался использовать $ compile, но он создал бесконечный цикл и переполнение стека, поэтому ясно, что если это ответ, мне нужна помощь!   -  person Toby Eggitt    schedule 18.06.2016
comment
Было бы легче дать вам менее широкий ответ о процессе в целом, если бы вы могли точно показать, что вы планируете делать с элементами DOM, а не просто регистрировать их содержимое. Могут быть более эффективные способы достижения вашей цели. Однако я опубликовал ответ, который может дать вам дополнительные подсказки.   -  person Claies    schedule 18.06.2016


Ответы (1)


В своей функции link вы можете использовать службу $compile для «завершения» процесса компиляции. что-то вроде следующего:

return {
  link: function(scope, element) {
    var template = '<ul><li ng-repeat=" item in list ">{{item}}</li></ul>';
    var linkFn = $compile(template);
    var content = linkFn(scope);
    element.append(content);
  }
}

Это создаст полный элемент DOM, который можно будет пройти. вы можете изменить content перед добавлением или element после добавления content.

Вы часто будете видеть стенограмму этого процесса, а именно:

var content = $compile(template)(scope);

person Claies    schedule 18.06.2016
comment
Большое спасибо за ваши усилия, Клэйс, я попытался внести изменение, которое, как мне кажется, вы предлагаете, в код (теперь оно находится в основном примере), но это ничего не меняет. Если я неправильно понял ваше предложение, я думаю, проблема в том, что ngRepeat выглядит так, как будто он обрабатывается отдельно, спустя много времени после завершения компиляции. Я также не знаю, что, кажется, поддерживает это, что шаблон был включен в вывод, который я вижу, но был изменен для использования формы комментариев директивы ngRepeat, что не было в оригинале. - person Toby Eggitt; 19.06.2016
comment
Но раз уж вы спросите, зачем я это делаю, то начну. Реальное использование (а не эта минимальная иллюстрация) - это список элементов с кнопками удаления. Я хочу создать карту, которая связывает ключи на кнопках удаления (изначально индексы, но они перестают быть по мере удаления элементов) с элементами html, которые должны быть $ animate.leave () - ed. Думаю, я мог бы просто найти включающий элемент html, содержащий нажатую кнопку, но казалось хорошей идеей настроить все это заранее. К тому же, это кажется разумным занятием ... - person Toby Eggitt; 19.06.2016
comment
Я думаю, что проблема, с которой я столкнулся, заключается в том, что механизм ссылок и все его варианты предназначены для обработки и использования директивы. То, что я на самом деле пытаюсь сделать, - это обработать расширение ngRepeat, что представляет собой совершенно другую историю, по сути не имеющую отношения, и происходит позже. По сути, то, чего я действительно пытаюсь достичь, потребует от меня возиться с функцией ссылки директивы ngRepeat, а не моей директивы включающего шаблона. По-прежнему кажется, что если бы я правильно понял жизненный цикл, я мог бы это сделать, но я думаю, что сейчас я пойду другим путем. - person Toby Eggitt; 19.06.2016
comment
Главный вопрос, который у меня есть, - почему вы пытаетесь изменить HTML после того, как ваша директива отображает повтор, когда вы можете просто интегрировать то, что хотите, в шаблон повторения. - person Claies; 19.06.2016
comment
Я на самом деле не пытаюсь модифицировать HTML, я пытаюсь его разобрать (ну, это немного грандиозно - я пытаюсь выяснить, что там было помещено). Я попытался описать конечную функциональную цель парой комментариев назад (и действительно добился того, чтобы мой код работал должным образом, используя альтернативный подход, который я здесь изложил). Но концептуально кажется, что это должно быть возможно, и были бы другие варианты использования, чтобы иметь возможность узнать, что было сгенерировано, один раз, сразу после генерации, вместо того, чтобы ждать, пока не начнут взаимодействовать с этим сгенерированным кодом и выполнить анализ тогда. - person Toby Eggitt; 19.06.2016