Mettre à jour la variable de portée parent dans AngularJS

113

J'ai deux contrôleurs, l'un enveloppé dans un autre. Maintenant, je sais que la portée enfant hérite des propriétés de la portée parent, mais existe-t-il un moyen de mettre à jour la variable de portée parent? Jusqu'à présent, je n'ai trouvé aucune solution évidente.

Dans ma situation, j'ai un contrôleur de calendrier dans un formulaire. Je voudrais mettre à jour les dates de début et de fin de la portée parent (qui est le formulaire) afin que le formulaire ait les dates de début et de fin lorsqu'il est soumis.

Malcr001
la source
sonne comme votre contrôleur de calendrier devrait être une directive.
Jonah le

Réponses:

193

Vous devez utiliser un objet (pas une primitive) dans la portée parent et vous pourrez ensuite le mettre à jour directement à partir de la portée enfant

Parent:

app.controller('ctrlParent',function($scope){
    $scope.parentprimitive = "someprimitive";
    $scope.parentobj = {};
    $scope.parentobj.parentproperty = "someproperty";
});

Enfant:

app.controller('ctrlChild',function($scope){
    $scope.parentprimitive = "this will NOT modify the parent"; //new child scope variable
    $scope.parentobj.parentproperty = "this WILL modify the parent";
});

Démo de travail : http://jsfiddle.net/sh0ber/xxNxj/

Voir Quelles sont les nuances de l'héritage prototypique / prototypique de portée dans AngularJS?

Dan
la source
1
J'obtiens cette erreur lorsque j'essaye de mettre en œuvre ceci: «Impossible de définir la propriété« parentproperty »de non défini».
Malcr001
Pouvez-vous envoyer votre code? Cela fonctionne dans la démo de violon. Si votre contrôle de calendrier utilise la portée isolate, il n'héritera pas de la portée parent, vous devez donc transmettre la valeur à la portée de la directive.
Dan
Désolé, j'ai oublié cette question. Je l'ai accepté parce que j'ai finalement réussi à le faire fonctionner avec l'aide de cette réponse.
Malcr001
Je comprends que mettre le {{parentobj.parentproperty}} dans l'élément div ctrlParent est ce qui déclare l'objet parentobj et définit cet objet comme étant dans la portée ctrlParent. Est-ce une supposition correcte ?
Stephane
1
Merci, cela fonctionne! Je devrais certainement lire à ce sujet (héritage prototypique et primitifs). Pouvez-vous recommander une bonne lecture qui explique un peu plus que votre lien SO?
jvannistelrooy
116

Il existe une autre façon de faire cette tâche et de ne pas utiliser la $scope.$parentvariable.

Préparez simplement une méthode pour modifier la valeur dans la portée parent et utilisez-la dans l'enfant un. Comme ça:

app.controller('ctrlParent',function($scope) {
  $scope.simpleValue = 'x';
  $scope.changeSimpleValue = function(newVal) {
    $scope.simpleValue = newVal;
  };
});

app.controller('ctrlChild',function($scope){
    $scope.changeSimpleValue('y');
});

Cela fonctionne également et vous donne plus de contrôle sur les changements de valeur.

Vous pouvez ensuite appeler aussi la méthode même en HTML comme: <a ng-click="changeSimpleValue('y')" href="#">click me!</a>.

Ravbaker
la source
1
Bonne solution! cela fonctionne parce que lorsque quelque chose n'est pas trouvé dans la portée $ actuelle, Angular recherche dans celle $ parent. docs.angularjs.org/guide/scope (voir «Hiérarchies des portées»).
Elo
J'aime cette réponse, pas besoin de créer un objet inutile.
grimmdude
3
Futurs lecteurs: Tous ces cinq commentaires sont un peu erronés. Créer deux fonctions setter (qui sont des "objets inutiles") pour chaque variable est un kludge maladroit et inutile d'héritage et n'est pas la manière angulaire. Misko Hevery, le créateur d'Angular, donne une conférence dans laquelle il enseigne "Chaque fois que vous avez ng-model, il doit y avoir un point quelque part. Si vous n'avez pas de point, vous le faites mal." Misko video @ 29:19
Dan
comment puis-je appliquer cette solution à l'aide de la syntaxe controllerAS?
niran
6

Cela fonctionne également (mais je ne sais pas si cela suit les meilleures pratiques ou non)

app.controller('ctrlParent',function($scope) {
    $scope.simpleValue = 'x';
});

app.controller('ctrlChild',function($scope){
    $scope.$parent.simpleValue = 'y';
});
DynamicNate
la source
1
Vous avez raison, utiliser $ scope. $ Parent.value fonctionnera dans la plupart des cas, mais ce n'est généralement pas la meilleure idée à utiliser de manière intensive car cela peut être difficile à gérer dans des projets plus grands et plus compliqués.
Alex Johnson
4

Lorsque vous affectez un attribut primitif à une portée, il est toujours local à la portée (éventuellement créé à la volée), même si une portée parente a un attribut du même nom. Ceci est une décision de conception, et une bonne IMHO.

Si vous avez besoin de modifier une primitive (entiers, booléens, chaînes) dans la portée parent, à partir de la vue, vous en avez besoin pour être un attribut d'un autre objet dans cette portée, donc l'affectation peut lire:

<a ng-click="viewData.myAttr = 4">Click me!</a>

et il sera, à son tour:

  1. obtenir l' viewDataobjet à partir de la portée dans laquelle il est défini
  2. attribuez 4 à son myAttrattribut.
réécrit
la source
4

Pour accéder aux variables déclarées dans le parent, nous devrions utiliser $ parent dans le contrôleur enfant ou le fichier modèle

Dans le contrôleur

$scope.$parent.varaiable_name

Dans un modèle html

ng-model="$parent.varaiable_name"
Nibu
la source