Collegamento vs compilazione vs controller


529

Quando si crea una direttiva, è possibile inserire il codice nel compilatore, nella funzione di collegamento o nel controller.

Nei documenti, spiegano che:

  • le funzioni di compilazione e collegamento sono utilizzate in diverse fasi del ciclo angolare
  • i controller sono condivisi tra le direttive

Tuttavia, per me non è chiaro quale tipo di codice dovrebbe andare dove.

Ad esempio: è possibile creare funzioni in compilazione e averle collegate all'ambito nel collegamento o collegare solo funzioni all'ambito nel controller?

In che modo i controller sono condivisi tra le direttive, se ogni direttiva può avere il proprio controller? I controller sono davvero condivisi o sono solo le proprietà dell'ambito?



Forse una panoramica più completa delle funzioni della direttiva: direttive angolari - quando usare compilazione, controller, pre-link e post-link .
Izhaki,

1
Ho scritto un post con un diagramma del ciclo di vita della direttiva (fase di creazione). Forse aiuta qualcuno: filimanjaro.com/2014/…
media Joe

Risposte:


470

Compilare:

Questa è la fase in cui Angular compila effettivamente la tua direttiva. Questa funzione di compilazione viene chiamata una sola volta per ogni riferimento alla direttiva specificata. Ad esempio, supponiamo di utilizzare la direttiva ng-repeat. ng-repeat dovrà cercare l'elemento a cui è collegato, estrarre il frammento HTML a cui è collegato e creare una funzione modello.

Se hai utilizzato Manubri, sottolineatura modelli o equivalenti, è come compilare i loro modelli per estrarre una funzione modello. A questa funzione modello si passano i dati e il valore restituito di quella funzione è l'html con i dati nei posti giusti.

La fase di compilazione è quella fase in Angolare che restituisce la funzione modello. Questa funzione modello in angolare è chiamata funzione di collegamento.

Fase di collegamento:

La fase di collegamento è dove si collegano i dati ($ scope) alla funzione di collegamento e dovrebbe restituirti l'html collegato. Poiché la direttiva specifica anche dove va questo html o cosa cambia, è già buono andare. Questa è la funzione in cui si desidera apportare modifiche all'html collegato, ovvero l'html a cui sono già associati i dati. In angolare se si scrive codice nella funzione di collegamento è generalmente la funzione post-collegamento (per impostazione predefinita). È una specie di callback che viene chiamato dopo che la funzione di collegamento ha collegato i dati con il modello.

Controller:

Il controller è un luogo in cui si inserisce una logica specifica della direttiva. Questa logica può anche entrare nella funzione di collegamento, ma poi dovresti mettere quella logica sull'ambito per renderla "condivisibile". Il problema è che corromperesti il ​​campo di applicazione con le tue direttive, cosa che in realtà non è qualcosa che ci si aspetta. Qual è quindi l'alternativa se due direttive vogliono parlarsi / cooperare tra loro? Ovviamente potresti mettere tutta quella logica in un servizio e quindi fare in modo che entrambe queste direttive dipendano da quel servizio, ma ciò comporta solo un'altra dipendenza. L'alternativa è fornire un controller per questo ambito (di solito isolare l'ambito?) E quindi questo controller viene iniettato in un'altra direttiva quando quella direttiva "richiede" l'altra.


67
Per chiarire: compilare compila il modello da utilizzare in tutta la pagina. Linker è legato a ciascuna istanza. Giusto? Il controller funziona quindi tra le istanze.
Zlatko,

4
@CMCDragonkai per ogni controllerfunzione direttiva viene eseguita dopo la compilazione, ma prima pre-link in un ramo di albero DOM locale. Inoltre controllere le pre-linkfunzioni vengono eseguite attraversando il ramo DOM locale in modo dall'alto verso il basso . Successivamente post-linkviene eseguito in modo bottom-up .
Artem Platonov,

9
È solo un casino se non lo capisci. C'è una ragione per fare ciò che fa.
Demisx

3
Questa è la risposta tecnica corretta, tuttavia, mi rimangono ancora domande su quando dovrei usare la funzione di collegamento.
Nicholas Marshall,

2
Usiamo controllerinvece che linkovunque? In modo che non sia necessario modificare il codice in futuro se il metodo deve essere condiviso o una logica da introdurre ?. Ci sono insidie ​​nell'usare controllertutto il tempo invece del link?
JPS,

99

Volevo aggiungere anche ciò che il libro di O'Reily AngularJS del team di Google ha da dire:

Controller: crea un controller che pubblica un'API per comunicare attraverso le direttive. Un buon esempio è la comunicazione da direttiva a direttiva

Collegamento: modifica programmatica delle istanze degli elementi DOM risultanti, aggiunta di listener di eventi e impostazione dell'associazione dati.

Compila: modifica a livello di codice del modello DOM per le funzionalità attraverso copie di una direttiva, come quando viene utilizzato in ng-repeat. La funzione di compilazione può anche restituire funzioni di collegamento per modificare le istanze dell'elemento risultante.


Il tuo link thinkster.io non può essere guardato senza pagare. Non è il mio link, ma forse questo è più adatto: toddmotto.com/directive-to-directive-communication-with-require
R. van Twisk,

51

A directiveconsente di estendere il vocabolario HTML in modo dichiarativo per la creazione di componenti Web. L' ng-appattributo è una direttiva, così è ng-controllere tutto il resto ng- prefixed attributes. Le direttive possono essere attributes, tagso addirittura class names, comments.

Come nascono le direttive ( compilatione instantiation)

Compilare: useremo la compilefunzione per entrambi manipulateil DOM prima che venga visualizzato e restituiamo una linkfunzione (che gestirà il collegamento per noi). Questo è anche il posto dove mettere tutti i metodi che devono essere condivisi con tutta la instancespresente direttiva.

link: utilizzeremo la linkfunzione per registrare tutti i listener su un elemento DOM specifico (clonato dal modello) e impostare i nostri collegamenti alla pagina.

Se impostati nella compile()funzione, sarebbero stati impostati una sola volta (che spesso è ciò che si desidera). Se impostati nella link()funzione, verrebbero impostati ogni volta che l'elemento HTML è associato ai dati nell'oggetto.

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

     }
   };
});

CompileLa funzione restituisce la funzione pree postlink. Nella funzione pre-link abbiamo il modello di istanza e anche l'ambito da controller, ma il modello non è associato all'ambito e non ha ancora contenuto escluso.

Postla funzione link è dove post link è l'ultima funzione da eseguire. Ora il transclusionè completo the template is linked to a scopee il view will update with data bound values after the next digest cycle. L' linkopzione è solo una scorciatoia per impostare una post-linkfunzione.

controller: il controller della direttiva può essere passato a un'altra fase di collegamento / compilazione della direttiva. Può essere iniettato in altre direttive come mezzo da utilizzare nella comunicazione inter-direttiva.

Devi specificare il nome della direttiva da richiedere - Dovrebbe essere associato allo stesso elemento o al suo genitore. Il nome può essere preceduto da:

?  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.

Utilizzare la parentesi quadra [‘directive1′, ‘directive2′, ‘directive3′]per richiedere controller con più direttive.

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
hai detto che hai mostrato come ottenere parentDirectiveCtrl nel controller del bambino ... in questo esempio il bambino non ha un controller, ma piuttosto la funzione di collegamento ... Al momento non sono bloccato su questo problema, quindi potrebbe non essere così importante, ma una domanda curiosa.
alockwood05,

13

Inoltre, un buon motivo per utilizzare una funzione controller vs. link (poiché entrambi hanno accesso all'ambito, all'elemento e agli attr) è perché è possibile passare qualsiasi servizio disponibile o dipendenza in un controller (e in qualsiasi ordine), mentre non puoi farlo con la funzione link. Nota le diverse firme:

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

vs.

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

2
Si prega di lasciare un commento per spiegare il punto quando si vota una risposta. Grazie
svassr il

53
Non ero il downvoter, ma questo non è strettamente corretto perché è ancora possibile iniettare qualsiasi dipendenza richiesta nella direttiva stessa, ad esempio: module.directive('myDirective', function($window) { etc.... È quindi possibile accedervi dall'interno della funzione di collegamento.
Mike Chamberlain,

1
questo sembra essere direttamente errato in quanto è possibile inserire servizi nella funzione di collegamento
Codice Whisperer

1
@JoshRibakoff Il risultato finale è lo stesso, si ha accesso al servizio nella funzione di collegamento. Non importa se viene dichiarato negli argomenti della funzione o meno. A questo proposito Mike Chamberlain ha ragione
Connor Wyatt il

1
@ cwyatt1 Stavo correggendo il linguaggio, il plnkr non mostra l'iniezione in una funzione link () perché quella non è una caratteristica che Angular ha. Potresti pensare che io sia pedante ma il commento dei metamattici delinea già numerose differenze importanti tra ciò che fa quel plunkr e ciò che fa l'iniezione a un controller. L'OP chiede quali sono le differenze e ci sono differenze.
Josh Ribakoff,

10

questo è un buon esempio per comprendere le fasi della direttiva 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
Potrebbe illustrare il motivo per cui questo codice di esempio aiuterebbe a capire la differenza tra link, compilee controller?
cel sharp

sai come una requiredirettiva d può essere iniettata nel controller di una direttiva dipendente?
alockwood05,

Esempio codepen: Errore non rilevato: [$ injector: modulerr] Impossibile creare un'istanza del modulo myapp a causa di: Errore: [$ injector: unpr] Fornitore sconosciuto: slngStylePrelinkProvider
rofrol

7
  • compilare : usato quando è necessario modificare il modello di direttiva, come aggiungere una nuova espressione, aggiungere un'altra direttiva all'interno di questa direttiva
  • controller : utilizzato quando è necessario condividere / riutilizzare i dati $ scope
  • link : è una funzione utilizzata quando è necessario collegare il gestore eventi o manipolare DOM.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.