ng-bind произошло после моей директивы, поэтому у меня нет значения

У меня есть элемент div с директивой ng-bind:

<div ng-bind="sometext"></div>

У меня есть директива, которая получает элемент, проверяет его значение / текст и добавляет цвет к элементу в соответствии с содержимым. Я использую эту директиву вот так:

<div ng-bind="sometext" my-directive></div>

Проблема в том, что во время выполнения директивы в div нет значения или текста, потому что ng-bind еще не произошел.
Я получаю текст с помощью element.text ().
Любой идея, как сделать текст доступным внутри моей директивы?


person Naor    schedule 11.01.2014    source источник
comment
вам нужно будет изменить приоритет вашей директивы, чтобы она запускалась после ng-bind. Я еще никогда ничего не делал с приоритетами, поэтому не могу оказать вам слишком большую помощь.   -  person Matt Greer    schedule 12.01.2014
comment
@MattGreer: Я думал, решение будет примерно таким. Я видел код angularJS, и ng-bind не имеет приоритета. Мне нужно установить меньший приоритет, чем ng-bind, потому что я хочу, чтобы моя директива выполнялась последней. Есть идеи?   -  person Naor    schedule 12.01.2014
comment
На прошлой неделе у меня была аналогичная проблема, которую я решил, обернув $timeout часть моего кода, чтобы он оценил следующий цикл дайджеста, когда произошло связывание. Я не совсем доволен этим решением, но, возможно, его хватит для ваших нужд.   -  person towr    schedule 12.01.2014
comment
@Naor вы пробовали добавить priority: 1 в свою директиву? просто из любопытства, может, это действительно так просто?   -  person Matt Greer    schedule 12.01.2014


Ответы (3)


Изменить 2

Другой вариант - использовать ng-class или ng-style для изменения цвета текста. Тогда вам вообще не нужно создавать новую директиву.

Исходный ответ

Я бы вообще не зависел от директивы ng-bind ... На мой взгляд, это намного чище.

<div ng-bind="someModel" my-directive="someModel"></div>

А затем определите свою директиву как ...

angular.module('myApp').directive('myDirective', function() { 
    return {
        link: function(scope, element, attrs) {
            scope.$watch(attrs.myDirective, function(newValue, oldValue) {
              // Your Code here...
            });           
        }
    };      
});

Таким образом, вы можете использовать свою директиву, даже если у вас нет ng-bind в элементе (например, если вместо этого вы используете фигурные скобки).

<div my-directive="someModel">{{someModel}}</div>

В качестве альтернативы вы можете использовать attrs.$observe(...) (документацию). из scope.$watch(...).

<div ng-bind="someModel" my-directive="{{someModel}}"></div>

а также

angular.module('myApp').directive('myDirective', function() { 
    return {
        link: function(scope, element, attrs) {
            attrs.$observe('myDirective', function(interpolatedValue) {
              // Your Code here...
            });           
        }
    };      
});

Дополнительную информацию о различиях между scope.$watch(...) и attrs.$observe() можно найти здесь.

Изменить

Учитывая, что ваша директива в основном изменяет DOM после директивы ng-bind, почему бы не пропустить ng-bind все вместе?

<div my-directive="{{someModel}}"></div>

а также

angular.module('myApp').directive('myDirective', function() { 
    return {
        link: function(scope, element, attrs) {
            attrs.$observe('myDirective', function(interpolatedValue) {
              if (interpolatedValue) {
                // Modify interpolatedValue if necessary...
              }
              element.text(interpolatedValue == undefined ? '' : interpolatedValue);
            });           
        }
    };      
});
person rtcherry    schedule 11.01.2014
comment
Я использовал часы для значения атрибута. Это наиболее логичный поступок. Большое спасибо! - person Naor; 12.01.2014

Ваша директива может быть запущена до того, как ngBind привязал ее значение - и ваша директива, и ngBind имеют приоритет 0, поэтому любой из них может работать первым, подробнее об этом чуть позже, но давайте посмотрим на ngBind исходный код, чтобы увидеть корень проблемы:

var ngBindDirective = ngDirective(function(scope, element, attr) {
  element.addClass('ng-binding').data('$binding', attr.ngBind);

  scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
    element.text(value == undefined ? '' : value);
  });

});

Мы видим, что ngBind не обновляет сразу DOM, а скорее отслеживает атрибут ngBind. Таким образом, элемент не будет обновлен до тех пор, пока эти часы не будут запущены в следующем $digest цикле (поэтому $timeout работает).

Итак, один из вариантов - имитировать ngBind и поместить свои собственные часы в его атрибут - тогда вы будете обновляться всякий раз, когда ngBind результат изменится:

angular.module('myApp').directive('myDirective', function() { 
    return {
        priority: 1,
        link: function(scope,element,attrs) {
            scope.$watch(attrs.ngBind, function(newvalue) {
              console.log("element ",element.text());
            });           
        }
    };      
});

Вы заметите, что я установил приоритет на 1. Вы должны быть уверены, что часы этой директивы помещены после ngBind watch в очередь просмотра. Это гарантирует, что элемент был обновлен сначала ngBind.

По умолчанию функция ссылки директивы запускает пост-ссылку, поэтому $compile docs:

Директивы с большим числовым приоритетом составляются первыми. Функции перед связыванием также выполняются в порядке приоритета, но функции после связывания выполняются в обратном порядке.

Следовательно, поскольку ngBind имеет приоритет 0, все, что больше 0, гарантирует, что часы вашей директивы появятся после просмотра ngBind ..

демонстрационная скрипка

person KayakDave    schedule 11.01.2014
comment
Хороший ответ! Было бы неплохо сказать несколько слов, объясняющих, почему более высокий приоритет заставляет $watch, зарегистрированный в функции postLink, срабатывать после ngBind $watch :) - person gkalpak; 12.01.2014
comment
@ExpertSystem спасибо! Хороший момент - я немного рассказал об этом. - person KayakDave; 12.01.2014
comment
Если команда AngularJS не изменит приоритет ng-bind. Я настоятельно рекомендую вам не основывать поведение вашего кода на изменении результата ng-bind. - person rtcherry; 12.01.2014
comment
@rtcherry Я понимаю ваше беспокойство. Но на самом деле это не изменяет результаты ng-bind, а просто добавляет часы, которые следуют за ними. И, конечно же, Angular может изменить что угодно - но это будет помечено как критическое изменение - они публикуют свои приоритеты (например, делая приоритет ngRepeats 1000 заметным). - person KayakDave; 12.01.2014
comment
Ваш код не изменяет результат, но исходный вопрос касается чтения текстового значения и последующего изменения цвета. - person rtcherry; 12.01.2014
comment
@rtcherry достаточно честно. Я думаю об этом больше как о цепочке - например, о добавлении еще одного парсера в цепочку синтаксического анализа. Но я сосредоточился на Любой идее, как сделать текст доступным внутри моей директивы? В целом, я думаю, что наличие нескольких подходов к этому отлично подходит для SO. - person KayakDave; 12.01.2014

Вы можете использовать scope. $ Watch в функции ссылки и следить за изменениями модели. Каждый раз, когда значение изменяется, ng-bind будет срабатывать, и ваша директива также будет запущена, независимо от директивы bg-bind и зависит только от самой модели.

Извините, я не могу предоставить вам образец кода на планшете, отвечая на ваш вопрос.

person Kia Panahi Rad    schedule 11.01.2014