Avec la manière originale de définir les contrôleurs , l'accès à la portée du parent était assez trivial, car la portée enfant hérite de manière prototypique de son parent.
app.controller("parentCtrl", function($scope){
$scope.name = "Parent";
})
.controller("childCtrl", function($scope){
$scope.childName = "child of " + $scope.name;
});
<div ng-controller="parentCtrl">
{{name}}
<div ng-controller="childCtrl">
{{childName}}
</div>
</div>
L'approche Controller-As semble être la manière recommandée de déclarer un contrôleur. Mais avec Controller-As, l'approche ci-dessus ne fonctionne plus.
Bien sûr, je peux accéder à la portée parent avec pc.name
depuis la vue:
<div ng-controller="parentCtrl as pc">
{{pc.name}}
<div ng-controller="childCtrl as cc">
{{cc.childName}}
</div>
</div>
J'ai quelques problèmes avec cela (potentiel pour le code spaghetti), mais cette question concerne l'accès à la portée parent à partir du contrôleur enfant.
La seule façon dont je peux voir ce fonctionnement est:
app.controller("parentCtrl", function(){
this.name = "parent";
})
.controller("childCtrl", function($scope){
$scope.pc.name = "child of " + $scope.name;
// or
$scope.$parent.pc.name = "child of " + $scope.name;
// there's no $scope.name
// and no $scope.$parent.name
});
Alors maintenant, le contrôleur enfant doit connaître "pc
" - sauf que cela devrait (dans mon esprit) être limité à la vue. Je ne pense pas qu'un contrôleur enfant devrait savoir qu'une vue a décidé de déclarer un ng-controller="parentCtrl as pc"
.
Q: Quelle est donc la bonne approche?
MODIFIER:
Clarification: je ne cherche pas à hériter d'un contrôleur parent. Je cherche à hériter/changer la portée partagée. Donc, si je modifiais le premier exemple, je devrais pouvoir faire ce qui suit:
app.controller("parentCtrl", function($scope){
$scope.someObj = {prop: "not set"};
})
.controller("childCtrl", function($scope){
$scope.someObj.prop = "changed";
});
Après des recherches, je suis arrivé à la réalisation suivante:
L'approche Controller-As ne remplace PAS l'utilisation de
$scope
. Les deux ont leur place et peuvent/doivent être utilisés ensemble judicieusement.
$scope
fait exactement ce que son nom implique: c'est-à-dire qu'il définit les propriétés de ViewModel sur le $scope
. Cela fonctionne mieux pour partager la portée avec des contrôleurs imbriqués qui peuvent utiliser le $scope
pour conduire leur propre logique ou pour la changer.Voici un exemple:
var app = angular.module('myApp', []);
// Then the controllers could choose whether they want to modify the inherited scope or not:
app.controller("ParentCtrl", function($scope) {
this.prop1 = {
v: "prop1 from ParentCtrl"
};
$scope.prop1 = {
v: "defined on the scope by ParentCtrl"
};
})
.controller("Child1Ctrl", function($scope) {})
.controller("Child2Ctrl", function($scope) {
// here, I don't know about the "pc" alias
this.myProp = $scope.prop1.v + ", and changed by Child2Ctrl";
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="ParentCtrl as pc">
<div ng-controller="Child1Ctrl">
<div>I know about the "pc" alias: {{pc.prop1.v}}</div>
</div>
<div ng-controller="Child2Ctrl as ch2">
<div>I only care about my own ViewModel: {{ch2.myProp}}</div>
</div>
</div>
Vous devriez faire comme:
html
<div ng-controller="ChildController as child">
<button type="button" ng-click="child.sayMe()">Say me!</button>
</div>
js
var app = angular.module('myApp', [])
app.controller('BaseController',function() {
this.me = 'Base';
this.sayMe= function() {
alert(this.me);
}
});
app.controller('ChildController', function($scope, $controller) {
var controller = $controller('BaseController as base', {$scope: $scope});
angular.extend(this, controller);
this.me = 'Child';
});
jetez un oeil à https://docs.angularjs.org/guide/controller
Pour toute personne souhaitant simplement accéder à la portée parent par programmation, utilisez le service $scope
, Recherchez la portée parent et accédez au nom utilisé pour le controllerAs
de la portée parent, par exemple:
$scope.$parent.someName.doSomething();