333 votes

AngularJS : Comment faire passer des variables entre contrôleurs ?

J'ai deux contrôleurs Angular :

function Ctrl1($scope) {
    $scope.prop1 = "First";
}

function Ctrl2($scope) {
    $scope.prop2 = "Second";
    $scope.both = Ctrl1.prop1 + $scope.prop2; //This is what I would like to do ideally
}

Je ne peux pas utiliser Ctrl1 à l'intérieur de Ctrl2 parce qu'il est indéfini. Cependant, si j'essaie de le passer comme ceci

function Ctrl2($scope, Ctrl1) {
    $scope.prop2 = "Second";
    $scope.both = Ctrl1.prop1 + $scope.prop2; //This is what I would like to do ideally
}

Je reçois une erreur. Quelqu'un sait-il comment faire ?

Faire

Ctrl2.prototype = new Ctrl1();

Échecs également.

NOTE : Ces contrôleurs ne sont pas imbriqués les uns dans les autres.

1 votes

Il existe de nombreux moyens, mais le meilleur est la montre angulaire. Toujours quand on utilise un framework, c'est la meilleure façon d'utiliser ses propres méthodes pour faire le travail. n'oubliez pas ceci

0 votes

J'ai trouvé ce blog très utile Blog

506voto

Gloopy Points 16421

Une façon de partager des variables entre plusieurs contrôleurs est de créer un service et l'injecter dans n'importe quel contrôleur où vous voulez l'utiliser.

Exemple de service simple :

angular.module('myApp', [])
    .service('sharedProperties', function () {
        var property = 'First';

        return {
            getProperty: function () {
                return property;
            },
            setProperty: function(value) {
                property = value;
            }
        };
    });

Utilisation du service dans un contrôleur :

function Ctrl2($scope, sharedProperties) {
    $scope.prop2 = "Second";
    $scope.both = sharedProperties.getProperty() + $scope.prop2;
}

Ceci est très bien décrit dans ce blog (Leçon 2 et suivantes en particulier).

J'ai constaté que si vous voulez lier ces propriétés à plusieurs contrôleurs, cela fonctionne mieux si vous liez la propriété d'un objet plutôt qu'un type primitif (booléen, chaîne, nombre) pour conserver la référence liée.

Exemple : var property = { Property1: 'First' }; au lieu de var property = 'First'; .


UPDATE : Pour (j'espère) rendre les choses plus claires voici un violon qui montre un exemple de :

  • Liaison aux copies statiques de la valeur partagée (dans monContrôleur1)
    • Liaison à une primitive (chaîne de caractères)
    • Liaison à la propriété d'un objet (sauvegardée dans une variable de portée)
  • Liaison à des valeurs partagées qui mettent à jour l'interface utilisateur lorsque les valeurs sont mises à jour (dans myController2)
    • Liaison à une fonction qui renvoie une primitive (chaîne de caractères)
    • Liaison avec la propriété de l'objet
    • Liaison bidirectionnelle avec une propriété d'un objet

5 votes

Dans ce cas - comment la portée de Ctrl2 "sait" quand sharedProperties.getProperty() change de valeur ?

5 votes

Si vous souhaitez que l'interface utilisateur soit mise à jour à chaque fois que la propriété est modifiée, vous pouvez changer l'adresse suivante both pour être une fonction et elle sera appelée/réévaluée pendant le processus de digestion angulaire. Voir ce violon pour un exemple. De plus, si vous vous liez à la propriété d'un objet, vous pouvez l'utiliser directement dans votre vue et celle-ci sera mise à jour lorsque les données seront modifiées, comme dans l'exemple suivant cet exemple .

12 votes

Si vous voulez détecter et réagir aux changements dans votre contrôleur, une option est d'ajouter l'option getProperty() à la portée et utiliser la fonction $scope.$watch comme dans cet exemple . J'espère que ces exemples vous aideront !

45voto

Dmitri Zaitsev Points 1012

J'aime illustrer des choses simples par des exemples simples :)

Voici une méthode très simple Service exemple :

angular.module('toDo',[])

.service('dataService', function() {

  // private variable
  var _dataObj = {};

  // public API
  this.dataObj = _dataObj;
})

.controller('One', function($scope, dataService) {
  $scope.data = dataService.dataObj;
})

.controller('Two', function($scope, dataService) {
  $scope.data = dataService.dataObj;
});

Et ici le jsbin

Et voici un très simple Factory exemple :

angular.module('toDo',[])

.factory('dataService', function() {

  // private variable
  var _dataObj = {};

  // public API
  return {
    dataObj: _dataObj
  };
})

.controller('One', function($scope, dataService) {
  $scope.data = dataService.dataObj;
})

.controller('Two', function($scope, dataService) {
  $scope.data = dataService.dataObj;
});

Et ici le jsbin


Si c'est trop simple, Voici un exemple plus sophistiqué

Aussi voir la réponse ici pour les commentaires sur les meilleures pratiques connexes

1 votes

Oui, je suis d'accord avec vous. Il faut toujours essayer de rendre les choses simples.

0 votes

Quel est l'intérêt de déclarer var _dataObj = {}; quand vous y renvoyez une référence directe.. ? Ce n'est pas privé . Dans le premier exemple, vous pouvez faire this.dataObj = {}; et dans le second return { dataObj: {} }; c'est une déclaration de variable inutile IMHO.

0 votes

@TJ Le but est de partager cette variable entre d'autres composants. Il s'agit d'un exemple de base illustrant le concept de partage. La variable EST privée à l'intérieur du bloc, puis vous l'exposez en tant que variable publique à l'aide du motif révélateur. De cette façon, il y a séparation des responsabilités entre la détention de la variable et son utilisation.

26voto

user2545722 Points 89

--- Je sais que cette réponse n'est pas pour cette question, mais je veux que les personnes qui lisent cette question et qui veulent gérer des services tels que les usines n'aient pas de problèmes en faisant ceci ----

Pour cela, vous devrez utiliser un service ou une usine.

Les services sont les suivants BONNES PRATIQUES pour partager des données entre des contrôleurs non imbriqués.

Une très très bonne annotation sur ce sujet du partage des données est comment déclarer les objets. Je n'ai pas eu de chance car je suis tombé dans un piège d'AngularJS avant d'avoir lu ce sujet, et j'ai été très frustré. Laissez-moi donc vous aider à éviter ce problème.

J'ai lu dans le "ng-book : The complete book on AngularJS" que les ng-models AngularJS qui sont créés dans les contrôleurs en tant que bare-data sont FAUX !

Un élément $scope doit être créé comme ceci :

angular.module('myApp', [])
.controller('SomeCtrl', function($scope) {
  // best practice, always use a model
  $scope.someModel = {
    someValue: 'hello computer'
  });

Et pas comme ça :

angular.module('myApp', [])
.controller('SomeCtrl', function($scope) {
  // anti-pattern, bare value
  $scope.someBareValue = 'hello computer';
  };
});

Ceci est dû au fait qu'il est recommandé (BEST PRACTICE) que le DOM (document html) contienne les appels en tant que

<div ng-model="someModel.someValue"></div>  //NOTICE THE DOT.

Ceci est très utile pour les contrôleurs imbriqués si vous voulez que votre contrôleur enfant puisse modifier un objet du contrôleur parent.....

Mais dans votre cas, vous ne voulez pas de scopes imbriqués, mais il y a un aspect similaire pour obtenir des objets des services vers les contrôleurs.

Disons que vous avez votre service 'Factory' et que dans l'espace de retour il y a un objetA qui contient un objetB qui contient un objetC.

Si, depuis votre contrôleur, vous voulez récupérer l'objet C dans votre champ d'application, c'est une erreur de dire :

$scope.neededObjectInController = Factory.objectA.objectB.objectC;

Ça ne marchera pas... Utilisez plutôt un seul point.

$scope.neededObjectInController = Factory.ObjectA;

Ensuite, dans le DOM, vous pouvez appeler l'objetC à partir de l'objetA. C'est une bonne pratique liée aux fabriques, et la plus importante, cela permettra d'éviter les erreurs inattendues et non rattrapables.

2 votes

Je pense que c'est une bonne réponse, mais elle est assez difficile à digérer.

17voto

Sanjeev Points 233

Solution sans création de service, en utilisant $rootScope :

Pour partager les propriétés entre les contrôleurs d'applications, vous pouvez utiliser le $rootScope d'Angular. Il s'agit d'une autre option pour partager des données, en les mettant à la disposition des autres.

Le moyen préféré de partager certaines fonctionnalités entre contrôleurs est le service. Pour lire ou modifier une propriété globale, vous pouvez utiliser $rootscope.

var app = angular.module('mymodule',[]);
app.controller('Ctrl1', ['$scope','$rootScope',
  function($scope, $rootScope) {
    $rootScope.showBanner = true;
}]);

app.controller('Ctrl2', ['$scope','$rootScope',
  function($scope, $rootScope) {
    $rootScope.showBanner = false;
}]);

Utilisation de $rootScope dans un modèle (Accès aux propriétés avec $Root) :

<div ng-controller="Ctrl1">
    <div class="banner" ng-show="$root.showBanner"> </div>
</div>

5 votes

À ce stade, vous utilisez des variables à portée globale, ce qui s'écarte de l'idée d'AngularJS, qui consiste à déterminer localement la portée de tout ce qui se trouve dans ses différentes structures. L'ajout d'un fichier de variables global permettrait d'obtenir le même résultat et faciliterait la recherche de l'endroit où la variable est définie à l'origine. Dans tous les cas, ce n'est pas une suggestion.

4 votes

@Organiccat - Je comprends votre préoccupation et c'est pourquoi j'ai déjà mentionné que la voie préférée sera celle des services, sans aucun doute. Mais oui, Angular fournit également ce moyen. C'est à vous de voir comment vous voulez gérer vos globaux. J'ai eu un scénario où cette approche a mieux fonctionné pour moi.

9voto

Juan Zamora Points 114

L'échantillon ci-dessus a fonctionné à merveille. J'ai juste fait une modification au cas où j'aurais besoin de gérer plusieurs valeurs. J'espère que cela vous aidera !

app.service('sharedProperties', function () {

    var hashtable = {};

    return {
        setValue: function (key, value) {
            hashtable[key] = value;
        },
        getValue: function (key) {
            return hashtable[key];
        }
    }
});

1 votes

J'ai également créé un exemple utilisant un service pour partager des données entre différents contrôleurs. J'espère que vous l'apprécierez. jsfiddle.net/juazammo/du53553a/1

1 votes

Même si cela fonctionne, c'est généralement la syntaxe pour .factory . A .service doit être utilisé "si vous définissez votre service en tant que type/classe", conformément à l'article 3.2.1. de la directive sur les services. docs.angularjs.org/api/auto/service/$provide#service

1 votes

Dmitri, tu as raison, mais les gars d'Angular, de mon point de vue, ont juste changé un peu le concept que j'avais entre les services (façades) et les usines.... oh well.....

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X