‘this’ vs $ scope dans les contrôleurs AngularJS

Dans la section “Créer des composants” de la page d’accueil d’AngularJS, vous trouverez cet exemple:

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

Notez comment la méthode select est ajoutée à $scope , mais la méthode addPane est ajoutée à this . Si je le change en $scope.addPane , le code se casse.

La documentation dit qu’il y a effectivement une différence, mais elle ne mentionne pas la différence:

Les versions précédentes de Angular (version 1.0 RC précédente) vous permettaient d’utiliser this méthode de manière interchangeable avec la méthode $scope , mais ce n’est plus le cas. À l’intérieur des méthodes définies dans la scope, this scope et celle de $scope sont interchangeables (la valeur angular la définit comme $scope ), mais pas dans le constructeur de votre contrôleur.

Comment this et $scope fonctionnent-ils dans les contrôleurs AngularJS?

“Comment this et $scope fonctionnent-ils dans les contrôleurs AngularJS?”

Réponse courte :

  • this
    • Lorsque la fonction constructeur du contrôleur est appelée, this s’agit du contrôleur.
    • Lorsqu’une fonction définie sur un object $scope est appelée, this s’agit de “l’étendue en vigueur lorsque la fonction a été appelée”. Cela peut (ou peut ne pas être!) Être la $scope laquelle la fonction est définie. Donc, à l’intérieur de la fonction, this et $scope peuvent ne pas être les mêmes.
  • $scope
    • Chaque contrôleur a un object $scope associé.
    • Une fonction de contrôleur (constructeur) est responsable de la définition des propriétés du modèle et des fonctions / comportements sur la $scope associée.
    • Seules les méthodes définies sur cet object $scope (et les objects de scope parent, si un inheritance prototypique est en jeu) sont accessibles depuis la vue HTML /. Par exemple, à partir de ng-click , de filtres, etc.

Réponse longue :

Une fonction de contrôleur est une fonction constructeur JavaScript. Lorsque la fonction constructeur s’exécute (par exemple, lorsqu’une vue est chargée), this (c’est-à-dire le “contexte de fonction”) est défini sur l’object contrôleur. Donc, dans la fonction constructeur du contrôleur “tabs”, lorsque la fonction addPane est créée

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

il est créé sur l’object contrôleur, pas sur $ scope. Les vues ne peuvent pas voir la fonction addPane – elles ont uniquement access aux fonctions définies sur $ scope. En d’autres termes, dans le HTML, cela ne fonctionnera pas:

 won't work 

Après l’exécution de la fonction constructeur du contrôleur “tabs”, nous avons les éléments suivants:

après fonction de constructeur de contrôleur de tabs

La ligne noire en pointillés indique l’inheritance prototypique – une scope d’isolement hérite de manière générique de Scope . (Il n’hérite pas de manière prototypique du champ d’application où la directive a été rencontrée dans le code HTML.)

Maintenant, la fonction de lien de la directive de volet veut communiquer avec la directive tabs (ce qui signifie en réalité qu’elle doit affecter les tabs isoler $ scope d’une certaine manière). Les événements peuvent être utilisés, mais un autre mécanisme consiste à demander à la directive de volet de disposer du contrôleur de tabulation. (Il semble ne pas y avoir de mécanisme pour que la directive de volet require la scope $ des tabs.)

Donc, cela pose la question suivante: si nous n’avons access qu’au contrôleur des tabs, comment pouvons-nous avoir access aux tabs pour isoler $ scope (ce que nous voulons vraiment)?

Eh bien, la ligne pointillée rouge est la réponse. La “scope” de la fonction addPane () (je fais référence à la scope / les fonctions de JavaScript ici) donne à la fonction l’access aux tabs isoler $ scope. C’est-à-dire que addPane () a access aux “tabs IsolateScope” dans le diagramme ci-dessus en raison d’une fermeture créée lors de la définition de addPane (). (Si nous définissons à la place addPane () sur l’object $ scope des tabs, la directive pane n’aurait pas access à cette fonction et n’aurait donc aucun moyen de communiquer avec les tabs $ scope.)

Pour répondre à l’autre partie de votre question: how does $scope work in controllers? :

Dans les fonctions définies sur $ scope, this propriété est définie sur “le $ scope en vigueur où / quand la fonction a été appelée”. Supposons que nous ayons le code HTML suivant:

 
log "this" and $scope - parent scope
log "this" and $scope - child scope

Et le ParentCtrl (uniquement) a

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

En cliquant sur le premier lien, vous verrez que this et $scope sont identiques, car ” la scope en vigueur lorsque la fonction a été appelée ” correspond à la scope associée à la commande ParentCtrl .

En cliquant sur le deuxième lien, vous découvrirez que this et $scope ne sont pas les mêmes, car ” la scope en vigueur lorsque la fonction a été appelée ” est la scope associée à ChildCtrl . Donc, ici, this est défini sur $scope de ChildCtrl . Dans la méthode, $scope est toujours la $scope du ParentCtrl .

Violon

J’essaie de ne pas utiliser this intérieur d’une fonction définie sur $ scope, car cela devient confus pour savoir quelle $ scope est affectée, surtout si l’on considère que ng-repeat, ng-include, ng-switch et directives peuvent créer leurs propres étendues enfants. .

La raison pour laquelle addPane est assigné à cela est à cause de la directive .

La directive de pane require: '^tabs' , qui place l’object contrôleur d’tabs d’une directive parente dans la fonction de lien.

addPane est assigné à this pour que la fonction de lien du pane puisse le voir. Ensuite, dans la fonction de lien du pane , addPane est juste une propriété du contrôleur de tabs , et il ne s’agit que de tabsControllerObject.addPane. La fonction de liaison de la directive de volet peut donc accéder à l’object contrôleur des tabs et donc accéder à la méthode addPane.

J’espère que mes explications sont suffisamment claires. C’est difficile à expliquer.

Je viens de lire une explication assez intéressante sur la différence entre les deux et une préférence croissante pour attacher des modèles au contrôleur et alias le contrôleur pour lier les modèles à la vue. http://toddmotto.com/digging-into-angulars-controller-as-syntax/ est l’article. Il ne le mentionne pas mais lors de la définition de directives, si vous avez besoin de partager quelque chose entre plusieurs directives et que vous ne voulez pas de service (il existe des cas légitimes de services), joignez les données au contrôleur de la directive parente. Le service $ scope fournit beaucoup de choses utiles, $ watch étant la plus évidente, mais si tout ce dont vous avez besoin pour lier des données à la vue, utiliser le contrôleur standard et le contrôleur comme indiqué dans le modèle est préférable.

Je vous recommande de lire le post suivant: AngularJS: “Controller as” ou “$ scope”?

Il décrit très bien les avantages de l’utilisation de “Controller as” pour exposer les variables sur “$ scope”.

Je sais que vous avez posé des questions précises sur les méthodes et non sur les variables, mais je pense qu’il vaut mieux s’en tenir à une technique et s’y conformer.

Donc, à mon avis, en raison du problème de variables abordé dans le post, il est préférable d’utiliser la technique “Controller as” et de l’appliquer aux méthodes.

Dans ce cours ( https://www.codeschool.com/courses/shaping-up-with-angular-js ), ils expliquent comment utiliser “this” et bien d’autres choses.

Si vous ajoutez une méthode au contrôleur via la méthode “this”, vous devez l’appeler dans la vue avec le nom du contrôleur “dot” votre propriété ou méthode.

Par exemple, en utilisant votre contrôleur dans la vue, vous pouvez avoir un code comme celui-ci:

  
Your first pane is {{aliasOfYourController.panes[0]}}

Les versions précédentes de Angular (version 1.0 RC précédente) vous permettaient d’utiliser cette méthode de manière interchangeable avec la méthode $ scope, mais ce n’est plus le cas. À l’intérieur des méthodes définies dans la scope, cette scope et celle de $ sont interchangeables (la valeur angular la définit comme $ scope), mais pas dans le constructeur de votre contrôleur.

Pour ramener ce comportement (est-ce que quelqu’un sait pourquoi cela a été changé?), Vous pouvez append:

 return angular.extend($scope, this); 

à la fin de votre fonction de contrôleur (à condition que $ scope ait été injecté dans cette fonction de contrôleur).

Cela a un bon effet d’avoir access à la scope parent via l’object contrôleur que vous pouvez obtenir avec child avec require: '^myParentDirective'

$ scope a un ‘this’ différent du contrôleur ‘this’. Ainsi, si vous placez un console.log (this) dans le contrôleur, il vous donnera un object (controller) et this.addPane () appenda la méthode addPane à l’object Controller. Mais la scope $ a une scope différente et toutes les méthodes de sa scope doivent être accédées par $ scope.methodName (). this.methodName() dans le contrôleur signifie append des méthodes à l’intérieur de l’object contrôleur. $scope.functionName() est en HTML et à l’intérieur

 $scope.functionName(){ this.name="Name"; //or $scope.myname="myname"//are same} 

Collez ce code dans votre éditeur et ouvrez la console pour voir …

        this $sope vs controller     
Comming From $SCOPE :{{firstName}}

Comming from $SCOPE:{{lastName}}

Should Come From Controller:{{nickName}}

Blank nickName is because nickName is attached to 'this' of controller.





{{message}}