Link vs Compile vs Controller


529

Wenn Sie eine Direktive erstellen, können Sie Code in den Compiler, die Link-Funktion oder den Controller einfügen.

In den Dokumenten erklären sie Folgendes:

  • Kompilierungs- und Verknüpfungsfunktion werden in verschiedenen Phasen des Winkelzyklus verwendet
  • Controller werden von Direktiven gemeinsam genutzt

Für mich ist jedoch nicht klar, welche Art von Code wohin gehen soll.

Beispiel: Kann ich beim Kompilieren Funktionen erstellen und diese an den Bereich im Link anhängen oder nur Funktionen an den Bereich im Controller anhängen?

Wie werden Controller von Direktiven gemeinsam genutzt, wenn jede Direktive einen eigenen Controller haben kann? Sind die Controller wirklich gemeinsam genutzt oder handelt es sich nur um die Scope-Eigenschaften?



Vielleicht eine umfassendere Übersicht über Direktivenfunktionen: Angular-Direktiven - wann Kompilierung, Controller, Pre-Link und Post-Link verwendet werden sollen .
Izhaki

1
Ich habe einen Beitrag mit einem Diagramm des Lebenszyklus der Richtlinie (Erstellungsphase) geschrieben. Vielleicht hilft es jemandem: filimanjaro.com/2014/…
Durchschnitt Joe

Antworten:


470

Kompilieren:

In dieser Phase kompiliert Angular Ihre Direktive. Diese Kompilierungsfunktion wird nur einmal für jeden Verweis auf die angegebene Direktive aufgerufen. Angenommen, Sie verwenden die Anweisung ng-repeat. ng-repeat muss das angehängte Element nachschlagen, das angehängte HTML-Fragment extrahieren und eine Vorlagenfunktion erstellen.

Wenn Sie HandleBars, Unterstreichungsvorlagen oder Ähnliches verwendet haben, können Sie deren Vorlagen kompilieren, um eine Vorlagenfunktion zu extrahieren. An diese Vorlagenfunktion übergeben Sie Daten, und der Rückgabewert dieser Funktion ist der HTML-Code mit den Daten an den richtigen Stellen.

Die Kompilierungsphase ist der Schritt in Angular, der die Vorlagenfunktion zurückgibt. Diese Schablonenfunktion im Winkel wird als Verknüpfungsfunktion bezeichnet.

Verbindungsphase:

In der Verknüpfungsphase hängen Sie die Daten ($ scope) an die Verknüpfungsfunktion an und es sollte Ihnen das verknüpfte HTML zurückgegeben werden. Da die Direktive auch angibt, wohin dieses HTML geht oder was es ändert, ist es bereits gut zu gehen. Dies ist die Funktion, mit der Sie Änderungen an der verknüpften HTML-Datei vornehmen möchten, dh an der HTML-Datei, an die bereits die Daten angehängt sind. Wenn Sie im Winkel Code in die Verknüpfungsfunktion schreiben, ist dies im Allgemeinen die Post-Link-Funktion (standardmäßig). Es ist eine Art Rückruf, der aufgerufen wird, nachdem die Verknüpfungsfunktion die Daten mit der Vorlage verknüpft hat.

Controller:

Der Controller ist ein Ort, an dem Sie eine richtlinienspezifische Logik eingeben. Diese Logik kann auch in die Verknüpfungsfunktion einfließen, aber dann müssten Sie diese Logik in den Bereich einfügen, um sie "gemeinsam nutzbar" zu machen. Das Problem dabei ist, dass Sie dann den Gültigkeitsbereich mit Ihren Direktiven beschädigen würden, was nicht wirklich erwartet wird. Was ist also die Alternative, wenn zwei Richtlinien miteinander sprechen / zusammenarbeiten möchten? Natürlich können Sie all diese Logik in einen Dienst einfügen und dann beide Anweisungen von diesem Dienst abhängig machen, aber das bringt nur eine weitere Abhängigkeit mit sich. Die Alternative besteht darin, einen Controller für diesen Bereich bereitzustellen (normalerweise Bereich isolieren?), Und dann wird dieser Controller in eine andere Direktive eingefügt, wenn diese Direktive die andere "erfordert".


67
Zur Verdeutlichung: compile kompiliert die Vorlage, die auf der gesamten Seite verwendet werden soll. Linker ist an jede Instanz gebunden. Recht? Der Controller arbeitet dann zwischen Instanzen.
Zlatko

4
@CMCDragonkai für jede Direktivenfunktion controllerwird nach der Kompilierung ausgeführt, jedoch zuvor pre-link in einem lokalen DOM-Baumzweig. Auch controllerund pre-linkFunktionen werden ausgeführt , um die lokale DOM Niederlassung in einem Durchlaufen Top-down - Weise. Danach post-linkwird von unten nach oben ausgeführt.
Artem Platonov

9
Es ist nur ein Durcheinander, wenn Sie es nicht verstehen. Es gibt einen Grund dafür, das zu tun, was es tut.
Demisx

3
Dies ist die richtige technische Antwort. Ich habe jedoch immer noch Fragen, wann ich die Link-Funktion verwenden soll.
Nicholas Marshall

2
Sollen wir controllerstatt linküberall verwenden? Damit ich den Code in Zukunft nicht mehr ändern muss, wenn die Methode gemeinsam genutzt oder eine Logik eingeführt werden muss? Gibt es Fallstricke bei der ständigen Verwendung controlleranstelle von Link?
JPS

99

Ich wollte auch hinzufügen, was das O'Reily AngularJS-Buch des Google-Teams zu sagen hat:

Controller - Erstellen Sie einen Controller, der eine API für die Kommunikation über Direktiven veröffentlicht. Ein gutes Beispiel ist die Richtlinie zur Richtlinie Kommunikation

Link - Ändern Sie die resultierenden DOM-Elementinstanzen programmgesteuert, fügen Sie Ereignis-Listener hinzu und richten Sie die Datenbindung ein.

Kompilieren - Ändern Sie programmgesteuert die DOM-Vorlage für Features über Kopien einer Direktive hinweg, wie bei Verwendung in ng-repeat. Ihre Kompilierungsfunktion kann auch Verknüpfungsfunktionen zurückgeben, um die resultierenden Elementinstanzen zu ändern.


Ihr thinkster.io-Link kann nicht ohne Bezahlung angesehen werden. Nicht mein Link, aber vielleicht ist dies besser geeignet: toddmotto.com/directive-to-directive-communication-with-require
R. van Twisk

51

Mit A directivekönnen Sie das HTML-Vokabular deklarativ erweitern, um Webkomponenten zu erstellen. Das ng-appAttribut ist eine Direktive, genau ng-controllerwie alle anderen ng- prefixed attributes. Richtlinien können sein attributes, tagsoder sogar class names, comments.

Wie Direktiven geboren werden ( compilationund instantiation)

Kompilieren: Wir werden die compileFunktion sowohl für manipulatedas DOM verwenden, bevor es gerendert wird, als auch eine linkFunktion zurückgeben (die die Verknüpfung für uns übernimmt). Hier können auch alle Methoden platziert werden, die mit allen instancesRichtlinien dieser Richtlinie geteilt werden müssen.

link: Mit dieser linkFunktion registrieren wir alle Listener für ein bestimmtes DOM-Element (das aus der Vorlage geklont wurde) und richten unsere Bindungen für die Seite ein.

Wenn sie in der compile()Funktion eingestellt wären, wären sie nur einmal eingestellt worden (was oft das ist, was Sie wollen). Wenn sie in der link()Funktion festgelegt sind, werden sie jedes Mal festgelegt, wenn das HTML-Element an Daten im Objekt gebunden wird.

<div ng-repeat="i in [0,1,2]">
    <simple>
        <div>Inner content</div>
    </simple>
</div>

app.directive("simple", function(){
   return {
     restrict: "EA",
     transclude:true,
     template:"<div>{{label}}<div ng-transclude></div></div>",        
     compile: function(element, attributes){  
     return {
             pre: function(scope, element, attributes, controller, transcludeFn){

             },
             post: function(scope, element, attributes, controller, transcludeFn){

             }
         }
     },
     controller: function($scope){

     }
   };
});

CompileFunktion gibt die preund postLink-Funktion zurück. In der Pre-Link-Funktion haben wir die Instanzvorlage und auch den Bereich aus dem controller, aber die Vorlage ist nicht an den Bereich gebunden und hat noch keinen transkludierten Inhalt.

PostBei der Link-Funktion ist die Post-Link-Funktion die letzte auszuführende Funktion. Jetzt transclusionist das abgeschlossen the template is linked to a scopeund das view will update with data bound values after the next digest cycle. Die linkOption ist nur eine Verknüpfung zum Einrichten einer post-linkFunktion.

Regler: Der Direktivencontroller kann an eine andere Direktivenverknüpfungs- / Kompilierungsphase übergeben werden. Es kann in andere Direktiven eingefügt werden, um es in der Kommunikation zwischen Direktiven zu verwenden.

Sie müssen den Namen der erforderlichen Anweisung angeben. Sie sollte an dasselbe Element oder dessen übergeordnetes Element gebunden sein. Dem Namen kann Folgendes vorangestellt werden:

?  Will not raise any error if a mentioned directive does not exist.
^  Will look for the directive on parent elements, if not available on the same element.

Verwenden Sie eine eckige Klammer, [‘directive1′, ‘directive2′, ‘directive3′]um einen Controller mit mehreren Anweisungen zu benötigen.

var app = angular.module('app', []);

app.controller('MainCtrl', function($scope, $element) {
});

app.directive('parentDirective', function() {
  return {
    restrict: 'E',
    template: '<child-directive></child-directive>',
    controller: function($scope, $element){
      this.variable = "Hi Vinothbabu"
    }
  }
});

app.directive('childDirective', function() {
  return {
    restrict:  'E',
    template: '<h1>I am child</h1>',
    replace: true,
    require: '^parentDirective',
    link: function($scope, $element, attr, parentDirectCtrl){
      //you now have access to parentDirectCtrl.variable
    }
  }
});

1
Sie haben erwähnt, dass Sie gezeigt haben, wie Sie die parentDirectiveCtrl in den Controller des Kindes einbinden können. In diesem Beispiel hat das Kind keinen Controller, sondern eine Verknüpfungsfunktion. Ich bin derzeit nicht mit diesem Problem beschäftigt, daher ist dies möglicherweise nicht der Fall so wichtig, aber eine merkwürdige Frage.
Alockwood05

13

Ein guter Grund für die Verwendung einer Controller- / Link-Funktion (da beide Zugriff auf den Bereich, das Element und die Attribute haben) ist, dass Sie jeden verfügbaren Dienst oder jede verfügbare Abhängigkeit an einen Controller (und in beliebiger Reihenfolge) übergeben können Mit der Link-Funktion können Sie das nicht tun. Beachten Sie die unterschiedlichen Signaturen:

controller: function($scope, $exceptionHandler, $attr, $element, $parse, $myOtherService, someCrazyDependency) {...

vs.

link: function(scope, element, attrs) {... //no services allowed

2
Bitte hinterlassen Sie einen Kommentar, um Ihren Standpunkt zu erläutern, wenn Sie eine Antwort ablehnen. Danke
svassr

53
Ich war nicht der Downvoter, aber das ist nicht genau richtig, da Sie immer noch die erforderliche Abhängigkeit in die Direktive selbst einfügen können, z module.directive('myDirective', function($window) { etc.... Darauf kann dann über die Link-Funktion zugegriffen werden.
Mike Chamberlain

1
Dies scheint einfach falsch zu sein, da Sie Dienste in die Link-Funktion
Code Whisperer

1
@JoshRibakoff Das Endergebnis ist das gleiche, Sie haben Zugriff auf den Dienst in der Link-Funktion. Es spielt keine Rolle, ob es in den Argumenten der Funktion deklariert ist oder nicht. In dieser Hinsicht ist Mike Chamberlain richtig
Connor Wyatt

1
@ cwyatt1 Ich habe die Sprache korrigiert. Das plnkr zeigt kein Injizieren in eine link () -Funktion an, da dies keine Funktion ist, die Angular hat. Sie mögen denken, ich bin pedantisch, aber der Metamatts-Kommentar beschreibt bereits zahlreiche wichtige Unterschiede zwischen dem, was dieser Plunkr tut, und dem, was das Injizieren in einen Controller bewirkt. Das OP fragt nach den Unterschieden, und es gibt Unterschiede.
Josh Ribakoff

10

Dies ist ein gutes Beispiel für das Verständnis der Richtlinienphasen http://codepen.io/anon/pen/oXMdBQ?editors=101

var app = angular.module('myapp', [])

app.directive('slngStylePrelink', function() {
    return {
        scope: {
            drctvName: '@'
        },
        controller: function($scope) {
            console.log('controller for ', $scope.drctvName);
        },
        compile: function(element, attr) {
            console.log("compile for ", attr.name)
            return {
                post: function($scope, element, attr) {
                    console.log('post link for ', attr.name)
                },
                pre: function($scope, element, attr) {
                    $scope.element = element;
                    console.log('pre link for ', attr.name)
                        // from angular.js 1.4.1
                    function ngStyleWatchAction(newStyles, oldStyles) {
                        if (oldStyles && (newStyles !== oldStyles)) {
                            forEach(oldStyles, function(val, style) {
                                element.css(style, '');
                            });
                        }
                        if (newStyles) element.css(newStyles);
                    }

                    $scope.$watch(attr.slngStylePrelink, ngStyleWatchAction, true);

                    // Run immediately, because the watcher's first run is async
                    ngStyleWatchAction($scope.$eval(attr.slngStylePrelink));
                }
            };
        }
    };
});

html

<body ng-app="myapp">
    <div slng-style-prelink="{height:'500px'}" drctv-name='parent' style="border:1px solid" name="parent">
        <div slng-style-prelink="{height:'50%'}" drctv-name='child' style="border:1px solid red" name='child'>
        </div>
    </div>
</body>

4
Könnten Sie das näher erläutern, warum würde dieser Beispielcode , den Unterschied zwischen helfen zu verstehen link, compileund controller?
Cel

Wissen Sie, wie eine required-Direktive in den Controller einer abhängigen Direktive eingefügt werden kann?
Alockwood05

Beispiel für einen Codepen: Nicht erfasster Fehler: [$ injizierer: modulerr] Fehler beim Instanziieren des Moduls myapp aufgrund von: Fehler: [$ Injektor: unpr] Unbekannter Anbieter: slngStylePrelinkProvider
rofrol

7
  • compile : Wird verwendet, wenn wir die Direktivenvorlage ändern müssen, z. B. einen neuen Ausdruck hinzufügen und eine weitere Direktive in diese Direktive einfügen
  • Controller : Wird verwendet, wenn $ scope-Daten freigegeben / wiederverwendet werden müssen
  • link : Dies ist eine Funktion, die verwendet wird, wenn ein Ereignishandler angehängt oder ein DOM bearbeitet werden muss.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.