oninit - templateurl angularjs




'this' vs $ scope nei controller AngularJS (5)

"Come funzionano this e $scope nei controller AngularJS?"

Risposta breve :

  • this
    • Quando viene chiamata la funzione del costruttore del controller, this è il controller.
    • Quando viene chiamata una funzione definita su un oggetto $scope , this è lo "scope in effect quando la funzione è stata chiamata". Questo può (o non può!) Essere l' $scope cui è definita la funzione. Quindi, all'interno della funzione, this e $scope potrebbero non essere gli stessi.
  • $scope
    • Ogni controller ha un oggetto $scope associato.
    • Una funzione controller (costruttore) è responsabile dell'impostazione delle proprietà del modello e delle funzioni / comportamento sul suo $scope associato.
    • Solo i metodi definiti su questo oggetto $scope (e sugli oggetti parent scope, se l'ereditarietà prototipica è in gioco) sono accessibili dalla vista HTML /. Ad esempio, da ng-click , filtri, ecc.

Risposta lunga :

Una funzione controller è una funzione di costruzione JavaScript. Quando viene eseguita la funzione di costruzione (ad esempio, quando una vista viene caricata), this (ovvero il "contesto della funzione") viene impostato sull'oggetto controller. Quindi nella funzione di costruzione del controller "tabs", quando viene creata la funzione addPane

this.addPane = function(pane) { ... }

è creato sull'oggetto controller, non su $ scope. Le viste non possono vedere la funzione addPane: hanno solo accesso alle funzioni definite su $ scope. In altre parole, nel codice HTML, questo non funzionerà:

<a ng-click="addPane(newPane)">won't work</a>

Dopo l'esecuzione della funzione di costruzione del controller "tabs", abbiamo il seguente:

La linea nera tratteggiata indica l'ereditarietà del prototipo: un ambito isolato ereditato prototipicamente da Scope . (Non eredita prototipicamente dall'ambito in cui si trovava la direttiva nel codice HTML).

Ora, la funzione di collegamento della direttiva del pannello vuole comunicare con la direttiva tabs (il che significa in realtà che ha bisogno di influenzare le schede isolare $ scope in qualche modo). È possibile utilizzare gli eventi, ma un altro meccanismo prevede che la direttiva del riquadro require il controller delle schede. (Sembra che non ci sia alcun meccanismo per la direttiva del pannello per require le schede $ scope.)

Quindi, questo solleva la domanda: se abbiamo solo accesso al controller delle schede, come possiamo accedere alle schede isolare $ scope (che è ciò che vogliamo veramente)?

Bene, la linea tratteggiata rossa è la risposta. Lo "scope" della funzione addPane () (mi riferisco all'ambito / chiusura delle funzioni di JavaScript qui) dà alla funzione l'accesso alle schede isolate $ scope. Ad esempio, addPane () ha accesso alle "schede IsolateScope" nel diagramma sopra a causa di una chiusura che è stata creata quando è stato definito addPane (). (Se invece abbiamo definito addPane () sull'oggetto $ tabs delle schede, la direttiva sul pannello non avrebbe avuto accesso a questa funzione, e quindi non avrebbe avuto modo di comunicare con le schede $ scope.)

Per rispondere all'altra parte della tua domanda: how does $scope work in controllers? :

All'interno delle funzioni definite su $ scope, this è impostato su "$ scope in vigore dove / quando è stata chiamata la funzione". Supponiamo di avere il seguente codice HTML:

<div ng-controller="ParentCtrl">
   <a ng-click="logThisAndScope()">log "this" and $scope</a> - parent scope
   <div ng-controller="ChildCtrl">
      <a ng-click="logThisAndScope()">log "this" and $scope</a> - child scope
   </div>
</div>

E il ParentCtrl ( ParentCtrl ) ha

$scope.logThisAndScope = function() {
    console.log(this, $scope)
}

Facendo clic sul primo collegamento verrà mostrato che this e $scope sono gli stessi, poiché " lo scope in vigore quando la funzione è stata chiamata " è l'ambito associato a ParentCtrl .

Facendo clic sul secondo link si rivelerà this e $scope non sono gli stessi, poiché " lo scope in vigore quando la funzione è stata chiamata " è l'ambito associato al ChildCtrl . Quindi qui, this è impostato su $scope ChildCtrl . All'interno del metodo, $scope è ancora l'ambito $ ParentCtrl .

Fiddle

Cerco di non utilizzare this all'interno di una funzione definita su $ scope, poiché diventa confuso su quale $ scope è interessato, specialmente considerando che ng-repeat, ng-include, ng-switch e le direttive possono tutti creare i propri ambiti figlio .

Nella sezione "Crea componenti" della homepage di AngularJS , c'è questo esempio:

controller: function($scope, $element) {
  var panes = $scope.panes = [];
  $scope.select = function(pane) {
    angular.forEach(panes, function(pane) {
      pane.selected = false;
    });
    pane.selected = true;
  }
  this.addPane = function(pane) {
    if (panes.length == 0) $scope.select(pane);
    panes.push(pane);
  }
}

Si noti come il metodo select viene aggiunto a $scope , ma il metodo addPane viene aggiunto a this . Se lo cambio in $scope.addPane , il codice si rompe.

La documentazione dice che in realtà c'è una differenza, ma non menziona qual è la differenza:

Le versioni precedenti di Angular (pre 1.0 RC) ti permettevano di usarlo in modo intercambiabile con il metodo $scope , ma non è più così. All'interno dei metodi definiti sull'ambito this e $scope sono intercambiabili (angolare imposta this a $scope ), ma non altrimenti all'interno del costruttore del controllore.

Come funzionano this e $scope nei controller AngularJS?


Le versioni precedenti di Angular (pre 1.0 RC) ti permettevano di usarlo in modo intercambiabile con il metodo $ scope, ma non è più così. All'interno dei metodi definiti sull'ambito questo e $ scope sono intercambiabili (angolare imposta questo a $ scope), ma non altrimenti all'interno del costruttore del controllore.

Per riportare questo comportamento (qualcuno sa perché è stato cambiato?) Puoi aggiungere:

return angular.extend($scope, this);

alla fine della funzione del controller (a condizione che $ scope sia stato iniettato su questa funzione del controller).

Questo ha un buon effetto di avere accesso all'ambito genitore tramite l'oggetto controller che è possibile ottenere in child con require: '^myParentDirective'


Ho appena letto una spiegazione piuttosto interessante sulla differenza tra i due, e una preferenza crescente per collegare i modelli al controller e alias il controller per legare i modelli alla vista. http://toddmotto.com/digging-into-angulars-controller-as-syntax/ è l'articolo. Non lo menziona ma quando si definiscono le direttive, se è necessario condividere qualcosa tra più direttive e non si desidera un servizio (esistono casi legittimi in cui i servizi sono una seccatura), allegare i dati al controller della direttiva padre. Il servizio $ scope fornisce molte cose utili, $ watch è il più ovvio, ma se tutto ciò che serve per legare i dati alla vista, usare il controller semplice e 'controller come' nel modello va bene, e probabilmente preferibile.


Il motivo per cui "addPane" è assegnato a causa della direttiva <pane> .

La direttiva del pane require: '^tabs' , che mette l'oggetto controller tabs da una direttiva parent, nella funzione link.

addPane è assegnato a this modo che la funzione di collegamento del pane possa vederlo. Quindi nella funzione di collegamento del pane , addPane è solo una proprietà del controller di tabs , ed è solo tabsControllerObject.addPane. Pertanto, la funzione di collegamento della direttiva del riquadro può accedere all'oggetto del controller delle schede e quindi accedere al metodo addPane.

Spero che la mia spiegazione sia abbastanza chiara ... è piuttosto difficile da spiegare.


Vi consiglio di leggere il seguente post: AngularJS: "Controller as" o "$ scope"?

Descrive molto bene i vantaggi dell'utilizzo di "Controller come" per esporre le variabili su "$ scope".

So che hai chiesto specificamente dei metodi e non delle variabili, ma penso che sia meglio attenersi a una tecnica ed essere coerenti con essa.

Quindi, secondo me, a causa del problema delle variabili discusso nel post, è meglio usare semplicemente la tecnica "Controller come" e applicarla anche ai metodi.





this