Доступ к DOM из области действия функции связывания. $ Watch: replace установлено на true vs false

Мне нужно управлять DOM из моей функции связывания.

Я заметил, что когда для параметра replace установлено значение false, я могу получить доступ к DOM (http://jsfiddle.net/bcsU8/)

//body of directive
return {
    restrict: 'A',
    replace: false,
    scope: {
        bar: '@myDir'
    },
    template: '<div id="{{bar}}">foo bar is <span>{{bar}}</span></div>',
    link: function(scope, element, attr) {
        scope.$watch('myDir', function(value) {
            console.log('In watch - scope.bar: ', scope.bar);
            console.log('DOM accesible? ', $("#"+scope.bar).length == 1);
        });
    }
};

но когда я установил для него значение true, я не могу (http://jsfiddle.net/PpXgb/)

return {
    restrict: 'A',
    replace: true,
    scope: {
        bar: '@myDir'
    },
    template: '<div id="{{bar}}">foo bar is <span>{{bar}}</span></div>',
    link: function(scope, element, attr) {
        scope.$watch('myDir', function(value) {
            console.log('In watch - scope.bar: ', scope.bar);
            console.log('DOM accesible? ', $("#"+scope.bar).length == 1);
        });
    }
};

Почему я не могу получить доступ к DOM при включенной замене? Я не нашел в документации ничего, что указывало бы на разницу между этими двумя случаями.

Из документации по функции связывания похоже, что DOM доступна после процесса связывания: (http://docs.angularjs.org/guide/directive)

Функция пост-связывания Выполняется после связывания дочерних элементов. Преобразование DOM с помощью функции пост-связывания безопасно.

Обратите внимание, что в моей области. $ Watch я фактически вызываю плагин jQuery, который ожидает, что DOM будет там, а не получить доступ к элементам напрямую через $ ()


person sanon    schedule 11.03.2013    source источник
comment
Боковое примечание - вы, возможно, уже знаете об этом, но в ваших примерах ng-repeat="bar in foo" должен быть на li, а не на ul   -  person Alex Osborn    schedule 12.03.2013
comment
спасибо @AlexOsborn, я обновил скрипки   -  person sanon    schedule 12.03.2013


Ответы (1)


В этом случае ваша проблема заключается в том, что элемент еще не прикреплен к DOM при запуске функции link. На самом деле это не проблема того, что вы пытаетесь сделать; проблема в том, что вы нарушаете передовой опыт, пытаясь получить доступ к элементу не через объект element, переданный в функцию link, а через селектор jQuery. Попробуйте использовать объект element, и я думаю, вы обнаружите, что ваш код внезапно работает.

Но есть предостережения относительно порядка выполнения методов директивы, поэтому есть некоторые случаи, когда это по-прежнему не сработает, но вы вряд ли столкнетесь с ними в базовой директиве. Точно так же вы должны прочитать страницу руководства по директивам, чтобы лучше понять, как AngularJS обрабатывает директивы.

person Josh David Miller    schedule 11.03.2013
comment
В моем коде я вызываю функцию в часах, которая ожидает, что дом будет там. Я веду консольный журнал, чтобы показать состояние DOM, которое испытывает функция, заключающаяся в том, что DOM иногда доступен, а иногда недоступен в функции связывания. - person sanon; 12.03.2013
comment
Вы не можете этого сделать. AngularJS не гарантирует, что узлы будут добавлены к DOM при выполнении функции link. В зависимости от вашего варианта использования функция postLink может работать лучше. Но я не могу сказать ничего более конкретного, не зная, что вы пытаетесь сделать. - person Josh David Miller; 12.03.2013
comment
Я использую плагин jQuery highcharts, который отображает диаграммы svg в div. Я ввожу блоки div диаграммы с помощью ng-repeat, привязанного к модели, содержащей все диаграммы. В функции часов у меня есть вызов highcharts. Он работает, если есть div, и не работает, если нет. Я тоже пробовал это с помощью compile postLink, но это не сработало, потому что я передаю идентификатор диаграммы в качестве атрибута (это то, что представляет scope.bar в примере). - person sanon; 12.03.2013
comment
Я не эксперт по Highcharts, но похоже, что вместо этого вы можете передать ссылку на элемент DOM: api.highcharts.com/highcharts#chart.renderTo. То есть просто передайте element вместо scope.bar. Это работает? - person Josh David Miller; 12.03.2013
comment
Нет, это дает мне: Ошибка: 'undefined' не является функцией (оценка 'a.setAttribute (b, c)') в Safari и TypeError: Object [object Object] не имеет метода 'setAttribute' в Chrome - person sanon; 12.03.2013
comment
Похоже, он позволяет использовать объект jQuery, но пытается использовать обычные функции DOM. Используйте element[0] и посмотрите, работает ли это. - person Josh David Miller; 12.03.2013