J'ai une application que je construis avec angulaire, j'ai environ 8-10 vues à construire. Toutes les vues ont un pied de page partagé, basé sur la vue et un ensemble de règles métier dont j'ai besoin pour afficher/masquer conditionnellement une partie du contenu du pied de page.
Alors. J'ai des contrôleurs pour chaque vue, puis un pour le pied de page. J'inclus la disposition de pied de page commune en utilisant ng-include, où le html que j'inclus fait référence au contrôleur de pied de page dans le ng-controller.
Index.html
<body ng-controller="MainCtrl as vm">
<p>Message from Main Controller '{{vm.mainMessage}}'</p>
<div ng-include="'commonFooter.html'"></div>
</body>
commonFooter.html
<div ng-controller="FooterCtrl as vm">
<p>Message from Footer Controller '{{vm.message}}'</p>
<p ng-show="vm.showSomthing">Conditional footer Content</p>
</div>
Je veux que chaque contrôleur de vues détermine l'état du pied de page et si un contenu spécifique est masqué ou non. (shouldDisplaySomthingInFooter ci-dessous)
app.controller('MainCtrl', function($scope) {
var vm = this;
vm.mainMessage= 'HEELO';
vm.shouldDisplaySomthingInFooter = true;
window.console.log('Main scope id: ' + $scope.$id);
});
Ensuite, j'avais prévu que dans le FooterController atteindrait de nouveau le contrôleur parent et retirerait les paramètres spécifiques pour activer/désactiver le contenu en fonction des règles métier.
app.controller('FooterCtrl', function($scope) {
var vm = this;
vm.message = 'vm footer';
window.console.log('Footer scope id: ' + $scope.$id);
window.console.log('Footer parent scope id: ' + $scope.$parent.$id);
window.console.log('Footer grandparent scope id: ' + $scope.$parent.$parent.$id);
window.console.log('Footer grandparent scope name: ' + $scope.$parent.$parent.mainMessage);
window.console.log('Footer grandparent scope condition: ' + $scope.$parent.$parent.shouldDisplaySomthingInFooter);
vm.showSomthing = false; //how to pull from parent scope to bind the ng-show to a value set in the parent from within a ng-include?
});
J'ai cet exemple ici: http://plnkr.co/edit/ucI5Cu4jjPgZNUitY2w0?p=preview
Ce que je trouve, c'est que lorsque j'atteins le champ d'application parent pour retirer le contenu, il revient comme non défini, et je ne sais pas pourquoi.
Je peux voir que les étendues sont imbriquées au niveau des grands-parents en vérifiant l'oscillid, je pense que c'est parce que le ng-include ajoute une couche d'étendue supplémentaire sous les étendues de la vue.
Points supplémentaires: si je ne peux pas avoir à utiliser l'objet $ scope et que je peux m'en tenir au var vm = this;
manière de le faire qui serait préférable. Mais les mendiants ne peuvent pas être des sélecteurs :)
app.controller('MainCtrl', function($scope) {
var vm = this;
Merci beaucoup d'avance.
Si vous définissez votre contrôleur externe comme vm
et votre contrôleur interne comme foo
, vous pouvez ensuite les séparer facilement et vous référer à vm dans le contrôleur interne.
[~ # ~] html [~ # ~] :
<body ng-controller="MainCtrl as vm">
<p>Message from Main Controller '{{vm.mainMessage}}'</p>
<div ng-include="'commonFooter.html'"></div>
</body>
CommonFooter.html :
<div ng-controller="FooterCtrl as footer">
<p>Message from Footer Controller '{{footer.message}}'</p>
<p ng-show="vm.shouldDisplaySomethingInFooter">Conditional footer Content</p>
</div>
app.js :
var app = angular.module('plunker', []);
app.controller('MainCtrl', function() {
var self = this;
self.mainMessage = 'Hello world';
self.shouldDisplaySomethingInFooter = true;
});
app.controller('FooterCtrl', function() {
var self = this;
self.message = 'vm footer';
});
Remarque: j'ai renommé votre var vm = this
à var self = this
pour plus de clarté et pour réduire la confusion entre vos vues et vos contrôleurs.
Production attendue:
Vous avez mal compris à quoi sert le contrôleur en tant que syntaxe ( voir documentation ). C'est juste un moyen d'exposer un contrôleur particulier sur votre portée locale, afin que vous puissiez accéder à ses propriétés à partir d'un modèle. Lorsque vous utilisez someController as vm
dans vos modèles parent et pied de page, vous ne créez en aucune façon une connexion entre les contrôleurs ou quelque chose comme ça. Vous définissez simplement une propriété vm
sur la portée de votre pied de page, donc lorsque vous l'utilisez dans votre modèle de pied de page, vous accédez au contrôleur du pied de page (et vous avez bloqué votre chemin vers le contrôleur parent).
Pour ce que vous essayez de faire, vous n'avez fondamentalement pas besoin du contrôleur comme syntaxe . Mettez correctement vos données sur $scope
et laissez la hiérarchie des étendues faire le reste pour vous.
Dans votre contrôleur parent:
$scope.features.rock = true;
$scope.features.roll = false;
Dans votre modèle de pied de page
<p ng-show="features.rock">...</p>
<p ng-show="features.roll">...</p>
Vous pouvez désormais également voir et modifier le features
de vos autres contrôleurs (car leurs étendues sont des descendants de l'étendue du contrôleur parent).
J'ai tripoté votre plunker, mais j'ai aussi changé var vm = this;
à $scope
, donc j'échoue à des points supplémentaires :-)
Je déconseille fortement l'utilisation de $scope.$parent
exactement pour la raison que vous montrez. Diverses directives telles que ng-include
, ng-show
etc, génèrent leurs propres étendues.
Vous n'avez aucun contrôle si quelqu'un à l'avenir modifie votre html et ajoute des étendues, intentionnellement ou non.
Je recommande d'utiliser des fonctions qui résident sur votre MainCtrl
et d'y accéder via l'héritage des étendues.
$scope.getShouldShow = function() {
return $scope.shouldDisplaySomthingInFooter;
};
$scope.setShouldShow = function(val) {
$scope.shouldDisplaySomthingInFooter = val;
};
$scope.getMainMessage = function () {
return $scope.mainMessage;
}
Et en les appelant:
<p ng-show="getShouldShow();">Conditional footer Content</p>
Et:
window.console.log('Footer grandparent scope name: ' + $scope.getMainMessage());
window.console.log('Footer grandparent scope condition: ' + $scope.getShouldShow());