4

Я получил директиву, которая работает следующим образом:Шаблон всегда компилируется со старым значением области видимости в директиве

http://jsfiddle.net/smithkl42/cwrgLd0L/23/

App.directive('prettify', ['$compile', function ($compile) { 
    var templateFn; 
    return { 
     restrict: 'E', 
     scope: { 
      target: '=' 
     }, 
     link: function (scope, element, attrs) { 
      if (!templateFn) { 
       var template = element.html(); 
       templateFn = $compile(template); 
      } 
      scope.$watch('target', function (newVal, oldVal) { 
       var compiled = templateFn(scope); 
       element.html(''); 
       element.append(compiled); 
       var html = element.html(); 
       var prettified = prettyPrintOne(html); 
       element.html(prettified); 
      }, true); 
     } 
    }; 
}]); 

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

enter image description here

Затем, если добавить символ в собственность, она показывает, что это, то есть, предыдущего значения scope.organization.message свойство:

enter image description here

отладка показывает, что значения в свойстве target директивы области действий являются правильными в момент компиляции.

Что я делаю неправильно? Есть ли что-то о функции шаблона, возвращаемой $compile, которая просматривает старые значения области? Или...?

(Смотрите также на этот вопрос, который привел к этому:. Using $compile in a directive triggers AngularJS infinite digest error)

ответ

1

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

Причина вашей проблемы с задержкой привязки связана с циклом дайджеста и тем, как Angular управляет изменениями в DOM. Когда обрабатывается изменение области видимости, все наблюдатели видимости обрабатываются до, любые изменения внесены в DOM. Таким образом, все изменения DOM объединяются в одну партию (по крайней мере, для этого цикла), поэтому вы не делаете сразу несколько обновлений, что может привести к множеству перерасчетов. Итак, когда вы вызываете element.html(), вы делаете это в точке, где DOM не обновлялся, чтобы отражать измененные значения в области.

В этом конкретном случае вы также выполняете кучу дополнительной работы - вызов templateFn даст вам объект jQuery (или jQLite) с нужным контентом - нет необходимости добавлять его в DOM, а затем возьмите его обратно, вы можете просто позвонить html() прямо против него.

Эта логика может все быть объединены (и правильно работать) следующим образом:

setTimeout(function() { 
    var compiled = templateFn(scope).html(); 
    var prettified = prettyPrintOne(compiled); 
    element.html(prettified); 
}, 0); 

Обертывание все в setTimeout заставляет логику оценивать после цикла дайджеста завершена.

Однако, вообще говоря, что реализация директивы немного неловко:

  • Если есть HTML шаблонный (например,<pre> и <code> теги), что требуется для каждого использования, которые должны быть включены в самой директивы через template или templateUrl свойства, а не ожидая, чтобы потребитель знал, что это требуется
  • Вы, вероятно, может уйти реализации этого без использования $compile - вы можете поместить вывод prettyPrintOne в область действия и просто привязать к нему в шаблоне, указанном в свойствах template или templateUrl, или вы можете использовать jQuery для получения ссылки на какой бы элемент не был контейнером (то есть, если это не элемент верхнего уровня) и используйте html(), чтобы установить его содержимое.
  • Если вам действительно нужно разрешить использование другого шаблонного HTML-содержимого внутри директивы, загляните в опцию transclude, определенную в directive guide.
+1

Спасибо! Очень хорошее объяснение. Вот рабочий jsfiddle: http://jsfiddle.net/smithkl42/cwrgLd0L/27/. –

Смежные вопросы