Question 'this' vs $ scope dans les contrôleurs AngularJS


dans le Section "Créer des composants" de la page d'accueil d'AngularJS, il y a 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);
  }
}

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

La documentation dit qu'il y a en fait une différence, mais elle ne mentionne pas la différence:

Les versions précédentes d'Angular (pré 1.0 RC) vous ont permis d'utiliser this interchangeable avec le $scope méthode, mais ce n'est plus le cas. Intérieur des méthodes définies sur le périmètre this et $scope sont interchangeables (jeux angulaires this à $scope), mais pas dans le constructeur de votre contrôleur.

Comment ça this et $scope travailler dans les contrôleurs AngularJS?


965
2017-07-23 02:55


origine


Réponses:


"Comment ça se passe this et $scope travailler dans les contrôleurs AngularJS? "

Réponse courte:

  • this
    • Lorsque la fonction de constructeur du contrôleur est appelée, this est le contrôleur.
    • Lorsqu'une fonction est définie sur un $scope l'objet est appelé, this est la "portée en vigueur lorsque la fonction a été appelée". Cela peut (ou peut ne pas être!) Être le $scope que la fonction est définie sur. Donc, à l'intérieur de la fonction, this et $scope mai ne pas être le même.
  • $scope
    • Chaque contrôleur a un associé $scope objet.
    • Une fonction de contrôleur (constructeur) est responsable de la définition des propriétés et des fonctions / comportements du modèle $scope.
    • Seules les méthodes définies sur ce $scope object (et les objets scope parent, si l'héritage prototypical est en jeu) sont accessibles à partir du HTML / view. Par exemple, de ng-click, filtres, etc.

Longue réponse:

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

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

il est créé sur l'objet contrôleur, pas sur $ scope. Les vues ne peuvent pas voir la fonction addPane - elles ont uniquement accès aux fonctions définies sur $ scope. En d'autres termes, dans le HTML, cela ne fonctionnera pas:

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

Après l'exécution de la fonction du constructeur du contrôleur "tabs", nous avons ce qui suit:

after tabs controller constructor function

La ligne noire en pointillé indique l'héritage prototype - une portée d'isolat hérite de manière prototypique de Portée. (Il n'hérite pas prototypiquement de la portée en vigueur où la directive a été rencontrée dans le code HTML.)

Maintenant, la fonction de lien de la directive du volet veut communiquer avec la directive tabs (ce qui signifie que les onglets doivent isoler $ scope d'une manière ou d'une autre). Des événements pourraient être utilisés, mais un autre mécanisme consiste à avoir la directive require le contrôleur d'onglets. (Il semble qu'il n'y ait aucun mécanisme pour que la directive du volet require les onglets $ scope.)

Donc, cela soulève la question: si nous avons seulement accès au contrôleur d'onglets, comment pouvons-nous accéder aux onglets isoler $ scope (ce qui est ce que nous voulons vraiment)?

Eh bien, la ligne pointillée rouge est la réponse. La «portée» de la fonction addPane () (je parle ici de la fonction / des fermetures de la fonction JavaScript ici) donne à la fonction l'accès aux onglets isoler $ scope. Par exemple, addPane () a accès aux "onglets 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'objet $ scope de l'onglet, la directive du volet n'aura pas accès à cette fonction et n'aura donc aucun moyen de communiquer avec les onglets $ scope.)

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

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

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

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 les mêmes, puisque "la portée en vigueur lorsque la fonction a été appelée"est la portée associée à la ParentCtrl.

En cliquant sur le deuxième lien, vous découvrirez this et $scope sont ne pas le même, puisque "la portée en vigueur lorsque la fonction a été appelée"est la portée associée à la ChildCtrl. Donc ici, this est réglé sur ChildCtrlde $scope. À l'intérieur de la méthode, $scope est toujours le ParentCtrl's $ scope

Violon

J'essaie de ne pas utiliser this à l'intérieur d'une fonction définie sur $ scope, car la portée de $ scope est affectée, d'autant plus que ng-repeat, ng-include, ng-switch et directives peuvent tous créer leurs propres étendues enfants.


949
2018-01-05 04:48



La raison «addPane» est attribuée à cela en raison de la <pane> directif.

le pane la directive ne require: '^tabs', qui place l'objet contrôleur tabs d'une directive parente, dans la fonction link.

addPane est affecté à this de sorte que la pane fonction de lien peut le voir. Puis dans le pane fonction de lien, addPane est juste une propriété du tabs contrôleur, et il est juste tabsControllerObject.addPane. Ainsi, la fonction de liaison de la directive du volet peut accéder à l'objet contrôleur d'onglets et donc accéder à la méthode addPane.

J'espère que mon explication est assez claire ... c'est un peu difficile à expliquer.


50
2017-07-23 15:20



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 ne voulez pas de service (il y a des cas légitimes où les services sont compliqués), attachez les données au contrôleur de la directive parent. Le service $ scope fournit beaucoup de choses utiles, $ watch étant le plus évident, mais si tout ce dont vous avez besoin pour lier des données à la vue, utiliser le contrôleur simple et 'controller as' dans le template est bien, et sans doute préférable.


26
2017-08-28 21:25



Dans ce cours(https://www.codeschool.com/courses/shaping-up-with-angular-js) ils expliquent comment utiliser "ceci" et beaucoup d'autres choses.

Si vous ajoutez une méthode au contrôleur via cette méthode, 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:

    <div data-ng-controller="YourController as aliasOfYourController">

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

    </div>

15
2017-09-24 07:29



Je vous recommande de lire le post suivant: http://codetunnel.io/angularjs-controller-as-or-scope/

il décrit très bien les avantages d'utiliser "Controller as" pour exposer des variables sur "$ scope".

Je sais que vous avez demandé spécifiquement des méthodes et non des variables, mais je pense qu'il vaut mieux s'en tenir à une technique et être cohérent avec elle.

Donc, à mon avis, en raison du problème des variables discuté dans le post, il est préférable d'utiliser simplement la technique "Controller as" et aussi de l'appliquer aux méthodes.


15
2017-11-03 10:31



Les versions précédentes d'Angular (pre 1.0 RC) vous ont permis d'utiliser cette   interchangeable avec la méthode $ scope, mais ce n'est plus le   Cas. À l'intérieur des méthodes définies sur la portée this et $ scope sont   interchangeable (angulaire définit ceci à $ scope), mais pas autrement   à l'intérieur de votre constructeur de contrôleur.

Pour rétablir ce comportement (quelqu'un sait-il pourquoi a-t-il été modifié?), Vous pouvez ajouter:

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 bel effet d'avoir accès à la portée parent via l'objet contrôleur que vous pouvez obtenir dans l'enfant avec require: '^myParentDirective'


3
2018-06-20 08:46



$ scope a un 'this' différent du contrôleur 'this'. Donc, si vous mettez un console.log (this) dans le controller, il vous donne un objet (controller) et this.addPane () ajoute addPane Method à l'objet Controller. Mais la portée de $ a une portée différente et toutes les méthodes dans sa portée doivent être accédées par $ scope.methodName (). this.methodName() à l'intérieur du contrôleur signifie ajouter des méthodes à l'intérieur de l'objet 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 ...

 <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>this $sope vs controller</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular.min.js"></script>
    <script>
        var app=angular.module("myApp",[]);
app.controller("ctrlExample",function($scope){
          console.log("ctrl 'this'",this);
          //this(object) of controller different then $scope
          $scope.firstName="Andy";
          $scope.lastName="Bot";
          this.nickName="ABot";
          this.controllerMethod=function(){

            console.log("controllerMethod ",this);
          }
          $scope.show=function(){
              console.log("$scope 'this",this);
              //this of $scope
              $scope.message="Welcome User";
          }

        });
</script>
</head>
<body ng-app="myApp" >
<div ng-controller="ctrlExample">
       Comming From $SCOPE :{{firstName}}
       <br><br>
       Comming from $SCOPE:{{lastName}}
       <br><br>
       Should Come From Controller:{{nickName}}
       <p>
            Blank nickName is because nickName is attached to 
           'this' of controller.
       </p>

       <br><br>
       <button ng-click="controllerMethod()">Controller Method</button>

       <br><br>
       <button ng-click="show()">Show</button>
       <p>{{message}}</p>

   </div>

</body>
</html>

0
2018-02-07 09:06