web-dev-qa-db-ja.com

AngularJSディレクティブでテンプレートを再レンダリングする方法は?

Twitterボタンを生成するディレクティブを作成しました。これらのボタンのスコープ変数は変更される可能性があるため、ボタンが発生したときにボタンを再構築する必要があります。現在、jQueryを使用して、リンクされた要素をempty()し、ボタンを再構築しています。

app.directive 'twitterShare', ($timeout, $window) ->
    restrict: 'E'
    template: '<a href="https://Twitter.com/share" 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()

代わりに、テンプレートを完全に再レンダリングするディレクティブを取得する方法はありますか?

25
Soviut

イベントが送信されるたびにトランスクルードされたコンテンツを再構築するために使用できる再利用可能なディレクティブを次に示します。

_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/

「トリガーの再リンク」ボタンをクリックするたびに、入力ボックスの内容がリセットされることに注意してください。これは、イベントがトリガーされるたびに入力ボックスが削除され、DOMに追加されるためです。

このディレクティブをそのまま使用するか、イベントの代わりにscope.$watch()によってトリガーされるように変更できます。

47
rob

いくつかのアドバイス:

  1. HTMLを手動で作成するのではなく、ディレクティブテンプレートを使用して変数をスコープにバインドします。この場合、テンプレートを再レンダリングする必要はありません。 Angularは、スコープのプロパティが変更されると、それ自体を更新します。

  2. attrs。$ observe 関数を使用して、属性値の変更時にコードを実行します

5

これを実現する別の方法は、ng-ifを使用することです。

例えば: <myDirective ng-if="renderdirective"></myDirective>

renderdirectiveがtrueになるまで、ディレクティブは作成されません。ディレクティブを削除し、新しい属性値を使用して再作成する場合、これは逆の方法でも機能します。

1
Muthukrishnan

あなたがやろうとしていることは、ディレクティブ内のコンパイル機能と一致し、htmlを再レンダリングします。試しましたか?

これは一種のハッキーな方法ですが、ディレクティブにng-if真偽変数を設定し、真偽変数をレンダリング、設定、および設定解除する場合:

angularjs:強制的に再レン​​ダリング/ディレクティブテンプレートを完全に更新

1
js_gandalf

@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の例はトランスクルードされ、再レンダリングおよび再コンパイルされます。

これは私にとって魅力的です。

正しい道を歩んでくれたロブに感謝します。

0
Mattijs