web-dev-qa-db-fra.com

Variables globales dans AngularJS

J'ai un problème où j'initialise une variable sur la portée dans un contrôleur. Il est ensuite modifié 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 restreint 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, c’est que le contrôleur qui l’initialise se fait appeler de nouveau par angular how, puis réinitialise 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, eh bien ce n’est pas vraiment global, alors ma question est la suivante: y at-il des exemples probants de ce travail avec la version actuelle d’angular?

341
Lightbulb1

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

$rootScope est un parent de toutes les étendues, ainsi les valeurs qui y sont exposées seront visibles dans tous les modèles et contrôleurs. L'utilisation de $rootScope est très simple, vous pouvez l'injecter dans n'importe quel contrôleur et modifier les valeurs dans cette étendue. Cela peut être pratique mais présente tous les problèmes de variables globales .

Les services sont des singletons que vous pouvez injecter à 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 contrôle bien meilleur 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'
  };
});

puis dans un contrôleur:

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

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

484

Si vous souhaitez simplement stocker une valeur, conformément à la documentation angulaire sur les fournisseurs , vous devez utiliser la recette Valeur:

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

Puis utilisez-le dans un contrôleur comme celui-ci:

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

La même chose peut être obtenue en utilisant un fournisseur, une fabrique ou un service, car ils ne constituent "que du sucre syntaxique en plus d'une recette de fournisseur", mais l'utilisation de Value permet d'obtenir ce que vous voulez avec une syntaxe minimale.

L'autre option consiste à 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 de variables globales dans d'autres langues. C'est conseillé à utiliser avec parcimonie.

Puisque toutes les portées héritent de $rootScope, si vous avez une variable $rootScope.data et que 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 souhaitez modifier cette valeur et la conserver sur tous vos contrôleurs, utilisez un objet et modifiez les propriétés en gardant à l'esprit que Javascript est passé par "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 JSFiddle

92
Dean Or

Exemple de "variables globales" AngularJS utilisant $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 qui fonctionne: http://jsfiddle.net/natefriedman/3XT3F/1/

34
NateFriedman

Dans l’intérêt d’ajouter une autre idée au pool wiki, mais qu’en est-il de AngularJS ' value et constant modules? Je commence tout juste à les utiliser moi-même, mais il me semble que ce sont probablement les meilleures options ici.

Remarque: au moment de la rédaction de ce document, Angular 1.3.7 est la dernière version stable. Je pense que ceux-ci ont été ajoutés à la version 1.2.0. Ils n'ont toutefois pas confirmé cela avec le journal des modifications.

Selon le nombre que vous devez définir, vous pouvez créer un fichier séparé pour eux. Mais je les définit généralement juste avant le bloc .config() de mon application pour un accès facile. Étant donné qu'il s'agit toujours de modules, vous devez vous en remettre à l'injection de dépendance, mais ils sont considérés comme "globaux" pour votre module d'application.

Par exemple:

angular.module('myApp', [])
  .value('debug', true)
  .constant('ENVIRONMENT', 'development')
  .config({...})

Puis à l'intérieur de n'importe quel contrôleur:

angular.module('myApp')
  .controller('MainCtrl', function(debug, ENVIRONMENT), {
    // here you can access `debug` and `ENVIRONMENT` as straight variables
  })

De la question initiale, on dirait en fait que des propriétés statiques sont nécessaires ici, que ce soit comme mutable (valeur) ou final (constante). C'est plus mon opinion personnelle qu'autre chose, mais je trouve que placer des éléments de configuration d'exécution sur le $rootScope devient trop compliqué, trop rapidement.

24
ZaLiTHkA
// app.js or break it up into seperate files
// whatever structure is your flavor    
angular.module('myApp', [])    

.constant('CONFIG', {
    'APP_NAME' : 'My Awesome App',
    'APP_VERSION' : '0.0.0',
    'GOOGLE_ANALYTICS_ID' : '',
    'BASE_URL' : '',
    'SYSTEM_LANGUAGE' : ''
})

.controller('GlobalVarController', ['$scope', 'CONFIG', function($scope, CONFIG) {

    // If you wish to show the CONFIG vars in the console:
    console.log(CONFIG);

    // And your CONFIG vars in .constant will be passed to the HTML doc with this:
    $scope.config = CONFIG;
}]);

Dans votre HTML:

<span ng-controller="GlobalVarController">{{config.APP_NAME}} | v{{config.APP_VERSION}}</span>
19
user742030
localStorage.username = 'blah'

Si vous êtes assuré d'être sur un navigateur moderne. Bien que sachez que vos valeurs seront toutes transformées en chaînes.

A également l'avantage pratique d'être mis en cache entre les recharges.

7
Kevin

S'il vous plaît, corrigez-moi si je me trompe, mais lorsque Angular 2.0 sera disponible, je ne crois pas que $rootScope sera présent. Ma conjecture est basée sur le fait que $scope est également supprimé. Il est évident que les contrôleurs existent toujours, mais pas de la manière ng-controller. Pensez à injecter des contrôleurs dans des directives. Comme la publication est imminente, il est préférable d’utiliser les services en tant que variables globales si vous souhaitez passer plus facilement de la version 1.X à la version 2.0.

6
jason328

Vous pouvez également utiliser la variable d'environnement $window pour qu'une variable globale déclarée en dehors d'un contrôleur puisse être vérifiée à l'intérieur d'un $watch.

var initWatch = function($scope,$window){
    $scope.$watch(function(scope) { return $window.globalVar },
        function(newValue) {
            $scope.updateDisplayedVar(newValue);
    });
}

Attention, le cycle de résumé est plus long avec ces valeurs globales, il n'est donc pas toujours mis à jour en temps réel. Je dois enquêter sur ce temps digérer avec cette configuration.

3
Megaman

Essayez ceci, vous ne forcerez pas à injecter $rootScope dans le contrôleur.

app.run(function($rootScope) {
    $rootScope.Currency = 'USD';
});

Vous ne pouvez l'utiliser que dans un bloc d'exécution, car ce dernier ne vous permettra pas d'utiliser le service $ rootScope.

0
Rahul Murari

Je viens de trouver une autre méthode par erreur:

Ce que j’ai fait est de déclarer une déclaration var db = null dessus de l’application, puis de la modifier dans le app.js puis, lorsque j’y ai accédé dans le controller.js, j’ai pu y accéder sans problème. Je ne suis pas au courant de certains problèmes avec cette méthode, mais je suppose que c'est une bonne solution.

0
Black Mamba

C'est en fait assez facile. (Si vous utilisez Angular 2+ de toute façon.)

Ajoutez simplement

declare var myGlobalVarName;

Quelque part dans la partie supérieure de votre fichier de composant (comme après les déclarations "import"), vous pourrez accéder à "myGlobalVarName" n'importe où dans votre composant.

0
Andy Corman