354 votes

Variables globales dans AngularJS

J'ai un problème où j'initialise une variable sur la portée dans un contrôleur. Elle est ensuite modifiée dans un autre contrôleur lorsqu'un utilisateur se connecte. Cette variable est utilisée pour contrôler des éléments tels que la barre de navigation et limiter l'accès à certaines parties du site en fonction du type d'utilisateur, il est donc important qu'elle conserve sa valeur. Le problème est que le contrôleur qui l'initialise, est appelé à nouveau par Angular et remet la variable à sa valeur initiale.

Je suppose que ce n'est pas la bonne façon de déclarer et d'initialiser les variables globales, car elles ne sont pas vraiment globales. Ma question est donc la suivante : quelle est la bonne façon de procéder et existe-t-il de bons exemples qui fonctionnent avec la version actuelle d'Angular ?

12 votes

Puisque c'est le résultat #1 de Google : Vous pouvez désormais utiliser app.constant() et app.value() pour créer des constantes et des variables à l'échelle de l'application. Plus d'informations ici : bit.ly/1P51PED

495voto

pkozlowski.opensource Points 52557

Vous avez essentiellement deux options pour les variables "globales" :

$rootScope est le parent de tous les scopes, de sorte que les valeurs qui y sont exposées seront visibles dans tous les modèles et contrôleurs. En utilisant l'option $rootScope est très facile car il suffit de l'injecter dans n'importe quel contrôleur et de modifier les valeurs dans cette portée. C'est peut-être pratique mais il y a tous les inconvénients de la problèmes des variables globales .

Les services sont des singletons que vous pouvez injecter dans n'importe quel contrôleur et exposer leurs valeurs dans la portée d'un contrôleur. Les services, étant des singletons, sont toujours "globaux" mais vous avez un bien meilleur contrôle sur l'endroit où ils sont utilisés et exposés.

L'utilisation des services est un peu plus complexe, mais pas tant que ça, voici un exemple :

var myApp = angular.module('myApp',[]);
myApp.factory('UserService', function() {
  return {
      name : 'anonymous'
  };
});

et ensuite dans un contrôleur :

function MyCtrl($scope, UserService) {
    $scope.name = UserService.name;
}

Voici le jsFiddle qui fonctionne : http://jsfiddle.net/pkozlowski_opensource/BRWPM/2/

141 votes

Desde el FAQ Angular : À l'inverse, ne créez pas un service dont le seul but dans la vie est de stocker et de renvoyer des bits de données.

7 votes

J'utilise le Graine d'Express + Angular par Btford . Si je définis une variable sur le $rootScope dans Controller1 et que je me déplace vers une autre url (alimentée par Controller2), je peux accéder à cette variable. Cependant, si je rafraîchis la page du Controller2, la variable n'est plus accessible sur $rootScope. Si j'enregistre les données de l'utilisateur à l'ouverture de session, comment puis-je m'assurer que ces données sont accessibles ailleurs, même en cas de rafraîchissement de la page ?

1 votes

J'ai ajouté une version plus complète de l'original. jsFiddle ici

98voto

Dean Or Points 461

Si vous voulez simplement stocker une valeur, selon la norme Documentation Angular sur les fournisseurs vous devez utiliser la recette Value :

var myApp = angular.module('myApp', []);
myApp.value('clientId', 'a12345654321x');

Utilisez-le ensuite dans un contrôleur comme celui-ci :

myApp.controller('DemoController', ['clientId', function DemoController(clientId) {
    this.clientId = clientId;
}]);

La même chose peut être obtenue à l'aide d'un fournisseur, d'une usine ou d'un service puisqu'il s'agit de "sucre syntaxique sur une recette de fournisseur", mais l'utilisation de Value permet d'obtenir ce que vous voulez avec une syntaxe minimale.

L'autre option est d'utiliser $rootScope mais ce n'est pas vraiment une option car vous ne devriez pas l'utiliser pour les mêmes raisons que vous ne devriez pas utiliser les variables globales dans d'autres langues. C'est conseillé à utiliser avec parcimonie.

Puisque tous les scopes héritent de $rootScope si vous avez une variable $rootScope.data et quelqu'un oublie que data est déjà défini et crée $scope.data dans une portée locale, vous rencontrerez des problèmes.


Si vous voulez modifier cette valeur et la faire persister dans tous vos contrôleurs, utilisez un objet et modifiez les propriétés en gardant à l'esprit que le Javascript est transmis par la fonction "copie d'une référence" :

myApp.value('clientId', { value: 'a12345654321x' });
myApp.controller('DemoController', ['clientId', function DemoController(clientId) {
    this.clientId = clientId;
    this.change = function(value) {
        clientId.value = 'something else';
    }
}];

Exemple de JSFiddle

1 votes

Lorsque j'ai modifié la valeur d'une vue, la nouvelle valeur n'est pas persistante. Comment cela se fait-il ? Pouvez-vous, s'il vous plaît, mettre à jour votre réponse et nous faire voir comment votre projet a été réalisé ? clientId peut être mis à jour ?

0 votes

@DeanOr Est-il possible de conserver la valeur mise à jour entre les rafraîchissements de la page ? La valeur est réinitialisée si je rafraîchis la page.

0 votes

Vous devrez utiliser autre chose pour cela, comme un cookie, un stockage local ou une base de données.

37voto

NateFriedman Points 163

Exemple d'utilisation des "variables globales" d'AngularJS $rootScope :

Le contrôleur 1 définit la variable globale :

function MyCtrl1($scope, $rootScope) {
    $rootScope.name = 'anonymous'; 
}

Le contrôleur 2 lit la variable globale :

function MyCtrl2($scope, $rootScope) {
    $scope.name2 = $rootScope.name; 
}

Voici un jsFiddle fonctionnel : http://jsfiddle.net/natefriedman/3XT3F/1/

2 votes

Cela ne fonctionne pas dans les vues de directives de portée isolée. Voir jsfiddle.net/3XT3F/7 . Mais vous pouvez utiliser $Root pour contourner ce problème. Voir jsfiddle.net/3XT3F/10 . Merci à @natefaubion para en le soulignant

2 votes

Lors du rafraîchissement, la valeur de $rootScope serait vide.

0 votes

Le codage en dur de $rootScope.name est égal à une certaine valeur En fait, nous devons le lire et le définir ici.

8voto

Kevin Points 1618
localStorage.username = 'blah'

Si vous êtes sûr d'être sur un navigateur moderne. Mais sachez que vos valeurs seront toutes transformées en chaînes de caractères.

Il a également l'avantage pratique d'être mis en cache entre les rechargements.

5 votes

Heh, je vais stocker toutes les variables via localStorage. Nous aurons même une sorte de persistance alors ! De plus, pour contourner la limitation des chaînes de caractères, stockons le .toString() d'une fonction et évaluons-le au besoin !

0 votes

Comme déjà mentionné par @Shaz, cela pose le problème de la persistance.

-2voto

pkdkk Points 365

Vous pouvez aussi faire quelque chose comme ceci .

function MyCtrl1($scope) {
    $rootScope.$root.name = 'anonymous'; 
}

function MyCtrl2($scope) {
    var name = $rootScope.$root.name;
}

3 votes

$rootScope est indéfini lorsque vous l'utilisez de cette façon.

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