web-dev-qa-db-fra.com

AngularJS: ng-include et ng-controller

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. outout from console in attached example

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.

26
DShorty

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.

Démo

[~ # ~] 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:

output showing the conditionally hidden\shown items

31
Kyle Muir

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

3
hon2a

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.

Plunker

$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());
2
Omri Aharon