Подтвердить что ты не робот

Как перерисовать шаблон в директиве AngularJS?

Я создаю директиву, которая генерирует кнопки Twitter. Поскольку переменные области действия на этих кнопках могут измениться, мне нужно перестроить кнопку, когда это произойдет. В настоящее время я использую jQuery для empty() связанного элемента и перестраиваю кнопку.

app.directive 'twitterShare', ($timeout, $window) ->
    restrict: 'E'
    template: '<a href="#" onclick="location.href='https://twitter.com/share'; return false;" class="twitter-share-button" data-text="{{ text }}" data-url="{{ url }}">Twitter</a>'
    scope:
        text: '@'
        url: '@'
    link: (scope, el, attrs) ->
        scope.$watch 'text', -> rebuild()
        scope.$watch 'url' , -> rebuild()

        rebuild = ->
            $(".twitter-share-button").remove()
            tweet = $ '<a>'
            .attr 'href', 'https://twitter.com/share'
            .attr 'id', 'tweet'
            .attr 'class', 'twitter-share-button'
            .attr 'data-lang', 'en'
            .attr 'data-count', 'none'
            .text 'Tweet'

            el.prepend tweet
            tweet.attr 'data-text', scope.text
            tweet.attr 'data-url', scope.url
            $window.twttr.widgets.load()

Есть ли способ заставить директиву полностью повторно отобразить шаблон?

4b9b3361

Ответ 1

Вот директива многократного использования, которую вы можете использовать, которая будет перестраивать транслируемый контент всякий раз, когда отправляется событие:

app.directive('relinkEvent', function($rootScope) {
    return {
        transclude: 'element',
        restrict: 'A',
        link: function(scope, element, attr, ctrl, transclude) {
            var previousContent = null;

            var triggerRelink = function() {
                if (previousContent) {
                    previousContent.remove();
                    previousContent = null;
                }

                transclude(function (clone) {
                    element.parent().append(clone);
                    previousContent = clone;
                });

            };

            triggerRelink();                
            $rootScope.$on(attr.relinkEvent, triggerRelink);

        }
    };

});

Вот демонстрация jsFiddle, как это работает: http://jsfiddle.net/robianmcd/ZQeU5/

Обратите внимание, что содержимое поля ввода получает reset каждый раз, когда вы нажимаете кнопку "Trigger Relink". Это связано с тем, что окно ввода удаляется и добавляется в DOM при каждом запуске события.

Вы можете использовать эту директиву как есть или изменить ее так, чтобы она срабатывала scope.$watch() вместо события.

Ответ 2

Несколько советов:

  • Использовать шаблон директивы и связывать переменные с областью, а не создавать HTML вручную. В этом случае вам не нужно повторно отображать шаблон. Angular будет обновлять его сам, когда изменяются свойства области.

  • Использовать функцию attrs. $наблюдать для запуска некоторого кода при изменении значения атрибута

Ответ 3

То, что вы пытаетесь сделать, соответствует функции компиляции в директивах, она повторно отображает html. Вы пробовали это?

Это своего рода хакерский способ сделать это, но в директиве вставлять в директиву правнущую переменную ng-if, а когда вы хотите рендерить, установить и отключить истинную переменную:

angularjs: принудительное повторное рендеринг/полное обновление шаблона директивы

Ответ 4

Другой способ добиться этого - использовать ng-if.

Например: <myDirective ng-if="renderdirective"></myDirective>

Директива не будет создана до тех пор, пока ваш renderdirective не будет прав. Это также будет работать наоборот, если вы хотите удалить эту директиву и позволить ей воссоздаваться с использованием новых значений атрибутов.

Ответ 5

Небольшое отклонение от ответа @rob:

import * as angular from 'angular';

class ReRenderDirective implements angular.IDirective {

  public restrict = 'A';
  public replace = false;
  public transclude = true;
  constructor( private $rootScope: angular.IRootScopeService, private $compile: angular.ICompileService ) {

  }

  public link = (
    scope: angular.IScope,
    element: angular.IAugmentedJQuery,
    attr: any,
    modelCtrl: any,
    transclude: angular.ITranscludeFunction ) => {

    let previousContent = null;

    let triggerRelink = () => {
      if ( previousContent ) {
        previousContent.remove();
        previousContent = null;
      }

      transclude(( clone ) => {
        element.append( clone );
        previousContent = clone;

        element.html( attr.compile );
        this.$compile( element.contents() )( scope );
      } );

    };

    triggerRelink();
    this.$rootScope.$on( attr.reRender, triggerRelink );

  }

}

export function reRenderFactory(): angular.IDirectiveFactory {

  var directive = ( $rootScope: angular.IRootScopeService, $compile: angular.ICompileService ) => new ReRenderDirective( $rootScope, $compile );
  directive.$inject = [ '$rootScope', '$compile' ];
  return directive;
}

Используйте это с помощью:

<div re-render="responsive">
  <header-component/>
</div>

и объединить его с $broadcast где-то в вашем коде:

this.$rootScope.$broadcast( 'responsive' );

Что я сделал, это слушать изменение размера страницы, которое затем запускает трансляцию. Исходя из этого, я могу изменить шаблон компонента с рабочего стола на мобильный. Поскольку header-component в этом примере завершается, он получает перезапись и перекомпилируется.

Это работает как прелесть для меня.

Спасибо Робу за то, что он меня на правильном пути.

Ответ 6

Использование ng-bind = "value" вместо {{value}} обновило мой кеш шаблона директивы для меня.

<myDirective><span ng-bind="searchResults.leads.results.length"></span></myDirective>

вместо

<myDirective><span>{{searchResults.leads.results.length}}</span></myDirective>