web-dev-qa-db-fra.com

Héritage du contrôleur AngularJS

AngularJS possède un héritage de contrôleur basé sur le DOM, comme indiqué dans la documentation angulaire.

<div ng-controller="BaseController">
    <p>Base Controller Value: {{value}}</p>
    <button ng-click="updateValue()">Update In Base</button>
    <div ng-controller="DerivedController">
        <p>Derived Controller Value: {{value}}</p>
        <button ng-click="updateValue()">Update In Derived</button>
    </div>
</div>

La variable de portée "valeur" est uniquement présente dans BaseController. Sur cette base, tout en modifiant la valeur d'une méthode dans BaseController ou DerivedController, je souhaite que les deux valeurs soient mises à jour. Mais seule la variable de portée individuelle est mise à jour.

Voici un violon montrant le même exemple: http://jsfiddle.net/6df6S/1/

Comment peut-on apporter des modifications à un niveau pour se propager à l'enfant immédiat et au parent immédiat de la portée actuelle.

Nous pouvons implémenter cela en utilisant 

$ scope. $ watch

Y a-t-il un moyen de faire cela sans l'utiliser ou de tels observateurs?

Modifier 1:

En utilisant $ scope. $ Watch, voici ce que je voulais dire

$scope.$watch("value", function () {
   $scope.$broadcast("childChangeListener"); //Downwards to all children scopes
   $scope.$emit("parentChangeListener"); //Upwards to all parent scopes
});

Je cherchais des moyens de mettre à jour la valeur sur tous les domaines sans utiliser un tel mécanisme.

28

Lorsque plusieurs contrôleurs ont besoin d'accéder aux mêmes données, un service doit être utilisé. Ne vous fiez pas à l'héritage de la portée, car cela restreint la manière dont vous pouvez écrire votre code HTML. Par exemple, à l'avenir, vous avez décidé que DerivedController ne devrait pas être un enfant de BaseController.

Votre service doit généralement fournir une API publique et masquer la mise en œuvre. Cela facilite la refactorisation des internes.

HTML:

<div ng-controller="BaseController">
    <p>Base Controller Value: {{model.getValue()}}</p>
    <button ng-click="model.updateValue('Value updated from Base')">Update In Base</button>
    <div ng-controller="DerivedController">
        <p>Derived Controller Value: {{model.getValue()}}</p>
        <button ng-click="model.updateValue('Value updated from Derived')">Update In Derived</button>
    </div>
</div>

JavaScript:

app.factory('sharedModel', function () {
    // private stuff
    var model = {
        value: "initial Value"
    };
    // public API
    return {
        getValue:    function() { 
           return model.value; 
        },
        updateValue: function(value) {
           model.value = value;
        }
    };
});

function BaseController($scope, sharedModel) {
    $scope.model = sharedModel;
}

function DerivedController($scope, sharedModel) {
    $scope.model = sharedModel;
}

Fiddle .

De plus, je ne recommande pas d'utiliser $ rootScope pour le partage entre contrôleurs.

50
Mark Rajcok

La liaison dans votre violon est directement sur une propriété dans la portée. L'héritage dont vous avez besoin peut être obtenu en ayant la liaison de données sur un objet dans l'étendue.

http://jsfiddle.net/2Dtyq/

scope.shared = {}    
scope.shared.value = "Something"

Au lieu de

scope.value= "Something"

Qu'est-ce qui se passe? 
Alors que DerivedController est construit, la portée transmise de manière prototype hérite de la portée de BaseController.
L'objet de portée de DerivedController n'a toujours pas sa propre propriété appelée "valeur". Par conséquent, il reste lié à la propriété qu'il a obtenue de la portée du parent. 
Maintenant, si vous cliquez sur le bouton Mettre à jour en base, cela se reflétera dans les deux liaisons . Dès que vous cliquerez sur le bouton Mettre à jour en dérivée, une nouvelle propriété nommée "valeur" est créé sur la portée du DerviedController. Par conséquent, la liaison à la propriété value du parent est rompue. Tout clic supplémentaire sur Update In Base n'actualise pas la deuxième liaison de données. 
Le placer dans un objet séparé empêche la création d'une nouvelle propriété, l'héritage est donc conservé.

8
San

Vous ne pouvez pas faire directement référence à la valeur de chaîne dans le contrôleur enfant. En raison de l'héritage du prototype, la propriété value sur la portée enfant (qui est créée lorsque vous utilisez un contrôleur enfant) crée cette propriété sur la portée enfant plutôt que de mettre à jour la propriété de la portée parent.

Votre portée n’est pas le modèle et nous devons donc éviter de polluer la variable $scope avec beaucoup de propriétés. Créez un objet de modèle et créez des sous-propriétés dessus. Cet objet peut ensuite être transmis avec les contrôleurs enfants\scope.

J'ai modifié votre jsfiddle pour expliquer le point ci-dessus.

De plus, je vous recommande vivement de passer par cette page wiki , pour comprendre les inconvénients de l’héritage prototype.

5
Chandermani

Jetez un coup d’œil à la méthode $ broadcast . Citant les docs:

Répartit un nom d'événement vers le bas dans toutes les étendues enfants (et leurs enfants ) En avertissant le ng. $ RootScope.Scope # $ enregistré sur les écouteurs.

2
Bruno

Cela se produit parce que ngController crée une nouvelle portée $ et que la référence à la valeur n’est pas la même. Vous pouvez résoudre cela en utilisant la propriété $parent comme ceci:

<div ng-controller="BaseController">
    <p>Base Controller Value: {{value}}</p>
    <div ng-controller="DerivedController">
        <p>Derived Controller Value: {{$parent.value}}</p>
    </div>
</div>

Et dans DerivedController, vous pouvez utiliser quelque chose comme ça: $scope.$parent.value

Mais le meilleur moyen de le mettre en œuvre est d’utiliser la syntaxe controllerAs.

<div ng-controller="BaseController as BaseController ">
<p>Base Controller Value: {{BaseController.value}}</p>
<div ng-controller="DerivedController">
    <p>Derived Controller Value: {{BaseController.value}}</p>
</div>

Et dans DerivedController, vous pouvez utiliser quelque chose comme ça: $scope.BaseController.value

Cela donne au code plus de lisibilité, parce que vous savez quel est le contrôleur que vous référencez. Plus d'informations à ce sujet dans ngController Docs ou Explorer la syntaxe «Controller as» de Angular par ToddMotto

0
Henrique Limas

Utilisez des objets au lieu d'utiliser une valeur primitive. Dans votre cas, définissez un objet comme celui-ci

$scope.obj = {"value":"base"}; 

et essayez (obj.value). ça va marcher.