'ceci' vs $scope dans les controllers AngularJS

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

noter 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 casse.

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

les versions précédentes D'Angular (pre 1.0 RC) vous permettaient d'utiliser this de façon 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 interchangeables (ensembles angulaires this à $scope ), mais pas à l'intérieur de votre constructeur de controller.

comment this et $scope fonctionne-t-il dans les contrôleurs AngularJS?

970
demandé sur Peter Mortensen 2012-07-23 06:55:47

7 réponses

"comment this et $scope fonctionne-t-il 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 définie sur un objet $scope est appelée, this est la portée en vigueur lorsque le la fonction a été appelée". Cela peut (ou ne peut pas! être le $scope que la fonction est définie sur. Donc, à l'intérieur de la fonction, this et $scope peut pas être le même.
  • $scope
    • chaque contrôleur a un objet associé $scope .
    • une fonction de contrôleur (constructeur) est chargée de définir les propriétés et les fonctions du modèle/le comportement son associé $scope .
    • seules les méthodes définies sur cet objet $scope (et les objets parent scope, si l'héritage prototypique est en jeu) sont accessibles à partir de la vue HTML/. Par exemple, de ng-click , filtres, etc.

longue réponse :

une fonction de contrôleur est une fonction de constructeur JavaScript. Quand la fonction constructeur s'exécute (e.g., quand une vue charge), this (i.e., le "contexte de la fonction") est défini à l'objet controller. Ainsi, dans la fonction" tabs "controller constructor, lorsque la fonction addPane est créée

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

il est créé sur l'objet controller, et non sur $scope. Les vues ne peuvent pas voir la fonction addPane -- elles n'ont accès qu'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 les "onglets" controller constructor function execute, nous avons le suivant:

after tabs controller constructor function

la ligne noire pointillée indique un héritage prototypique -- un isolat de portée hérite prototypiquement de de . (Il n'hérite pas prototypiquement du champ d'application en vigueur lorsque la directive a été rencontrée dans le HTML.)

maintenant, la fonction de lien de la directive pane veut communiquer avec la directive tabs (qui signifie vraiment qu'elle doit affecter les tabs isolent $scope d'une façon ou d'une autre). Les événements pourraient être utilisés, mais un autre mécanisme est d'avoir la directive pane require le contrôleur d'onglets. (Il ne semble pas y avoir de mécanisme pour la directive pane de require the tabs $scope.)

donc, cela nous amène à la question: si nous n'avons accès qu'au contrôleur des onglets, comment obtenir l'accès aux onglets isolent $scope (ce que nous voulons vraiment)?

eh Bien, la ligne pointillée rouge est la réponse. Le "scope" de la fonction addPane () (je me réfère à la fonction scope/closures de JavaScript ici) donne à la fonction l'accès aux onglets isolate $scope. C'est-à-dire: addPane() a accès aux "onglets IsolateScope" dans le diagramme ci-dessus en raison d'une fermeture qui a été créée lorsque addPane () a été défini. (Si nous avions plutôt défini addPane () sur l'objet tabs $scope, la directive pane n'aurait pas accès à cette fonction, et par conséquent elle n'aurait aucun moyen pour communiquer avec les onglets $champ d'application.)

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 à"$scope en vigueur où/quand la fonction a été appelée". Supposons que nous ayons le 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 (seulement) 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 au ParentCtrl .

en cliquant sur le deuxième lien, vous verrez que this et $scope sont et non identiques, puisque " la portée en vigueur lorsque la fonction a été appelée "est la portée associée au ChildCtrl . Donc ici, this est défini à ChildCtrl 's $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 il devient confus quelle $scope est affectée, surtout si l'on considère que ng-repeat, ng-include, ng-switch, et les directives peuvent toutes créer leurs propres scopes enfant.

954
répondu Mark Rajcok 2016-06-01 10:32:30

la raison pour laquelle" addPane "est attribué à ceci est en raison de la <pane> directive.

la directive pane fait require: '^tabs' , qui place l'objet de contrôle des onglets d'une directive parent, dans la fonction link.

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

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

51
répondu Andrew Joslin 2015-09-10 09:11:52

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 controller et alias le controller pour lier des 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 des directives, Si vous avez besoin de partager quelque chose entre plusieurs directives et que vous ne voulez pas un service (il y a des cas légitimes où les services sont hassle) puis 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, en utilisant le simple controller et 'controller as' dans le template est très bien, et probablement préférable.

26
répondu Derek 2014-08-28 21:25:47

je vous recommande de lire le post suivant: AngularJS: "Contrôleur" ou "$champ d'application"?

il décrit très bien les avantages d'utiliser" Controller as "pour exposer les variables au-dessus de"$scope".

je sais que vous avez demandé spécifiquement sur les méthodes et non les variables, mais je pense qu'il est préférable de s'en tenir à une technique et d'être cohérent avec elle.

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

17
répondu Liran Brimer 2018-08-23 09:29: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 controller par" cette "méthode, vous devez l'appeler dans la vue avec le nom du controller" dot " votre propriété ou méthode.

par exemple en utilisant votre controller dans la vue vous pouvez avoir un code comme ceci:

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

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

    </div>
15
répondu Sandro 2014-09-24 07:29:37

les versions précédentes D'Angular (pre 1.0 RC) vous ont permis d'utiliser ce de façon interchangeable avec le $champ d'application de la méthode, mais ce n'est plus la cas. A l'intérieur des méthodes définies sur le scope ceci et $scope sont interchangeables (angulaire définit ce à $champ), mais pas autrement à l'intérieur de votre contrôleur de constructeur.

ramener ce comportement (personne ne sait pourquoi était-il changé?), vous pouvez ajouter:

return angular.extend($scope, this);

à la fin de votre fonction de controller (à condition que $scope ait été injecté à cette fonction de controller).

cela a un bel effet d'avoir accès à l'objet parent scope via controller que vous pouvez obtenir en enfant avec require: '^myParentDirective'

3
répondu Kamil Szot 2014-06-20 08:46:34

$ scope a un 'Ceci' différent du controller 'ceci'.Donc si vous mettez une console.log(this) dans controller il vous donne un objet (controller) et ceci.addPane () ajoute la méthode addPane à l'objet controller. Mais le $scope a une portée différente et toutes les méthodes dans son champ d'application doivent être accessibles par $scope.methodName (). this.methodName() contrôleur intérieur signifie ajouter un objet contrôleur intérieur methos. $scope.functionName() est en HTML et à l'intérieur

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

Coller 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
répondu Aniket Jha 2018-02-07 09:06:17