Dans la section "Create Components" 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
, alors que la méthode addPane
est ajoutée à this
. Si je le change en $scope.addPane
, le code est cassé.
La documentation indique qu'il y a effectivement une différence, mais ne mentionne pas la différence:
Les versions précédentes de Angular (avant la version 1.0 RC) vous permettaient d'utiliser
this
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 les champsthis
et$scope
sont interchangeables (les ensembles angulairesthis
à$scope
), mais pas à l'intérieur du 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
this
est le contrôleur.$scope
est appelée, this
est "l'étendue en vigueur lorsque la fonction a été appelée". Cela peut (ou non) être le $scope
sur lequel la fonction est définie. Donc, dans la fonction, this
et $scope
peuvent ne pas être identiques.$scope
$scope
associé.$scope
associé.$scope
(et les objets de portée parents, si un héritage prototype est en cours de lecture) sont accessibles à partir de la vue HTML. Par exemple, à partir de ng-click
, filtres, etc.Longue réponse:
Une fonction de contrôleur est une fonction constructeur JavaScript. Lorsque la fonction constructeur s'exécute (par exemple, lors du chargement d'une vue), this
(c'est-à-dire le "contexte de la fonction") est défini sur l'objet contrôleur. Donc, dans la fonction 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, cela ne fonctionnera pas dans le code HTML:
<a ng-click="addPane(newPane)">won't work</a>
Après que la fonction constructeur du contrôleur "tabs" soit exécutée, voici ce qui suit:
La ligne noire en pointillés indique l'héritage du prototype - une portée isolée hérite de manière prototype de Scope . (Il n'hérite pas de manière prototypique de la portée en vigueur où la directive a été rencontrée dans le code HTML.)
Maintenant, la fonction link de la directive de volet veut communiquer avec la directive tabs (ce qui signifie vraiment qu'elle doit affecter les isolements de tabulation $ scope d'une manière ou d'une autre). Les événements peuvent être utilisés, mais un autre mécanisme consiste à utiliser la directive de volet require
comme contrôleur d'onglets. (Il semble n'y avoir aucun mécanisme pour la directive de volet pour require
les onglets $ scope.)
Cela pose donc la question suivante: si nous n’avons accès qu’au contrôleur des onglets, comment pouvons-nous avoir accès aux onglets isolate $ scope (ce que nous voulons vraiment)?
Eh bien, la ligne pointillée rouge est la réponse. La "portée" de la fonction addPane () (je fais ici référence à la fonction portée/fermetures de JavaScript) donne à la fonction l'accès aux onglets isolate $ 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éfinissions plutôt addPane () sur l'objet tabs $ scope, la directive du volet n'aurait pas accès à 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
est défini sur "le $ scope 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 la ParentCtrl
(uniquement) a
$scope.logThisAndScope = function() {
console.log(this, $scope)
}
En cliquant sur le premier lien, vous verrez que this
et $scope
sont identiques, puisque "la portée en vigueur lors de l'appel de la fonction _" est la portée associée à la ParentCtrl
.
En cliquant sur le deuxième lien, vous découvrirez que this
et $scope
sont pas identiques, puisque "la portée en vigueur lors de l'appel de la fonction" est la portée associée à la ChildCtrl
. Donc, ici, this
est défini sur ChildCtrl
's $scope
. Dans la méthode, $scope
est toujours la portée de la variable ParentCtrl
.
J'essaie de ne pas utiliser this
à l'intérieur d'une fonction définie sur $ scope, car cela crée de la confusion quant à la portée de $ scope, en particulier en considérant que ng-repeat, ng-include, ng-switch et des directives peuvent tous créer leurs propres portées enfants. .
La raison pour laquelle 'addPane' est attribué à cela est due à la directive <pane>
.
La directive pane
fait require: '^tabs'
, ce qui place l'objet contrôleur des tabulations d'une directive parent dans la fonction link.
addPane
est affecté à this
afin que la fonction de lien pane
puisse le voir. Ensuite, dans la fonction de lien pane
, addPane
est simplement une propriété du contrôleur tabs
et il ne s'agit que de tabsControllerObject.addPane. Ainsi, la fonction de liaison de la directive de volet peut accéder à l'objet contrôleur tabs et donc à la méthode addPane.
J'espère que mon explication est assez claire… c'est un peu 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 n'en parle 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 de service (il existe des cas légitimes où les services sont compliqués), attachez les données au contrôleur de la directive mère. Le service $ scope fournit beaucoup de choses utiles, $ watch étant le plus évident, mais si vous avez juste besoin de lier des données à la vue, utiliser le contrôleur brut et le "contrôleur en tant que" dans le modèle est correct et peut-être préférable.
Je vous recommande de lire le post suivant: AngularJS: "Controller as" ou "$ scope"?
Il décrit très bien les avantages d'utiliser "Controller as" pour exposer des variables sur "$ scope".
Je sais que vous avez spécifiquement posé des questions sur les méthodes et non sur 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 du problème des variables abordé dans l'article, il est préférable d'utiliser simplement la technique du "contrôleur en tant que" et de l'appliquer également aux méthodes.
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 "point" 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>
Les versions précédentes de Angular (avant la version 1.0 RC) vous permettaient de l'utiliser de manière interchangeable avec la méthode $ scope, mais ce n'est plus le Cas. À l'intérieur des méthodes définies sur les portées this et $ scope sont interchangeable (angular définit ceci à $ scope), mais pas autrement à l'intérieur de votre constructeur de contrôleur.
Pour ramener 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é à cette fonction de contrôleur).
Cela a un effet positif d'avoir accès à la portée parent via un objet contrôleur que vous pouvez obtenir dans l'enfant avec require: '^myParentDirective'
Ainsi, $ scope a un 'ceci' différent du contrôleur 'this'. Ainsi, si vous placez un console.log (this) dans le contrôleur, il vous donne un objet (contrôleur) et this.addPane () ajoute la méthode addPane à l’objet du contrôleur. Mais $ scope a une portée différente et toutes les méthodes de sa portée doivent être accédées par $ scope.methodName () .this.methodName()
à l'intérieur du contrôleur signifie d'ajouter des méthos à 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>