wake-up-neo.com

Wie wird eine Vorlage in einer AngularJS-Direktive erneut gerendert?

Ich habe eine Direktive erstellt, die Twitter-Schaltflächen generiert. Da sich die Bereichsvariablen auf diesen Schaltflächen möglicherweise ändern, muss ich die Schaltfläche neu erstellen, wenn sie auftritt. Derzeit verwende ich jQuery, um das verknüpfte Element zu empty() und die Schaltfläche neu zu erstellen.

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()

Gibt es eine Möglichkeit, die Direktive dazu zu bringen, die Vorlage vollständig neu zu rendern?

24
Soviut

Hier ist eine wiederverwendbare Direktive, die verwendet werden kann, um den übermittelten Inhalt immer dann neu zu erstellen, wenn ein Ereignis gesendet wird:

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);

        }
    };

});

Hier ist ein jsFiddle-Demo, wie es funktioniert: http://jsfiddle.net/robianmcd/ZQeU5/

Beachten Sie, dass der Inhalt des Eingabefelds jedes Mal zurückgesetzt wird, wenn Sie auf die Schaltfläche "Trigger Relink" klicken. Dies liegt daran, dass das Eingabefeld entfernt und dem DOM hinzugefügt wird, wenn das Ereignis ausgelöst wird. 

Sie können diese Direktive unverändert verwenden oder so ändern, dass sie von scope.$watch() anstelle eines Ereignisses ausgelöst wird.

46
rob

Einige Ratschläge:

  1. Verwenden Sie Direktionsvorlagen und binden Sie Variablen, anstatt HTML manuell zu erstellen. In diesem Fall müssen Sie die Vorlage nicht erneut rendern. Angular aktualisiert es selbst, wenn sich die Eigenschaften des Bereichs ändern.

  2. Verwenden Sie attrs. $ Observ - Funktion, um Code bei Änderung des Attributwerts auszuführen

5

Eine andere Möglichkeit, dies zu erreichen, ist die Verwendung von ng-if.

Zum Beispiel: <myDirective ng-if="renderdirective"></myDirective>

Die Direktive wird erst erstellt, wenn Ihre renderdirective nicht wahr ist. Dies funktioniert auch in umgekehrter Reihenfolge, wenn Sie die Direktive entfernen und mit den neuen Attributwerten neu erstellen lassen möchten.

1
Muthukrishnan

Was Sie mit der Kompilierfunktion innerhalb von Direktiven tun möchten, rendert die HTML-Datei neu. Hast du das probiert? 

Dies ist eine Art hackiger Weg, dies zu tun, aber der Anweisung wird eine ng-wenn-wahrheitliche Variable zugewiesen.

anglejs: Erzwingt das erneute Rendern/vollständige Aktualisierung einer Direktivenvorlage

1
js_gandalf

Kleine Variation der Antwort von @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;
}

Verwenden Sie dies mit:

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

und kombinieren Sie es mit einem Broadcast irgendwo in Ihrem Code:

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

Was ich getan habe, ist das Anpassen der Seitengröße, das dann die Übertragung auslöst. Auf dieser Grundlage kann ich die Vorlage einer Komponente von Desktop zu Mobile ändern. Da der header-component in diesem Beispiel transkludiert wird, wird er neu gerendert und neu kompiliert.

Das funktioniert für mich wie ein Zauber.

Danke Rob, dass du mich auf die richtige Spur gebracht hast.

0
Mattijs