Variables globales en AngularJS

Tengo un problema donde estoy inicializando una variable en el scope en un controlador. Luego se cambia en otro controlador cuando un usuario inicia sesión. Esta variable se usa para controlar cosas como la barra de navegación y restringe el acceso a partes del sitio según el tipo de usuario, por lo que es importante que mantenga su valor. El problema con esto es que el controlador que lo inicializa recibe de nuevo un llamado angular y luego restablece la variable a su valor inicial.

Supongo que esta no es la manera correcta de declarar e inicializar variables globales, bueno, no es realmente global, entonces mi pregunta es cuál es la forma correcta y ¿hay algún buen ejemplo alrededor de ese trabajo con la versión actual de angular?

Básicamente tienes 2 opciones para variables “globales”:

$rootScope es padre de todos los ámbitos, por lo que los valores expuestos allí serán visibles en todas las plantillas y controladores. Usar $rootScope es muy fácil ya que puede simplemente insertarlo en cualquier controlador y cambiar los valores en este ámbito. Puede ser conveniente, pero tiene todos los problemas de las variables globales .

Los servicios son únicos que puede inyectar a cualquier controlador y exponer sus valores en el scope de un controlador. Los servicios, siendo singletons son aún ‘globales’, pero usted tiene mucho mejor control sobre dónde se usan y se exponen.

Usar servicios es un poco más complejo, pero no tanto, aquí hay un ejemplo:

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

y luego en un controlador:

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

Aquí está el jsFiddle de trabajo: http://jsfiddle.net/pkozlowski_opensource/BRWPM/2/

Si solo desea almacenar un valor, de acuerdo con la documentación angular de Proveedores , debe usar la receta Valor:

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

Entonces úselo en un controlador como este:

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

Lo mismo se puede lograr utilizando un Proveedor, Fábrica o Servicio, ya que son “solo azúcar sintáctico sobre la receta del proveedor”, pero al usar el Valor logrará lo que desee con una syntax mínima.

La otra opción es usar $rootScope , pero no es realmente una opción porque no debe usarla por las mismas razones por las que no debe usar variables globales en otros idiomas. Se aconseja que se use con moderación.

Como todos los ámbitos heredan de $rootScope , si tiene una variable $rootScope.data y alguien olvida que los data ya están definidos y crea $scope.data en un ámbito local, se encontrará con problemas.


Si desea modificar este valor y persistir en todos sus controladores, use un objeto y modifique las propiedades, teniendo en cuenta que Javascript se pasa por “copia de una referencia” :

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

Ejemplo JSFiddle

Ejemplo de AngularJS “variables globales” usando $rootScope :

El controlador 1 establece la variable global:

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

El controlador 2 lee la variable global:

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

Aquí hay un jsFiddle de trabajo: http://jsfiddle.net/natefriedman/3XT3F/1/

Con el interés de agregar otra idea al conjunto de wikis, ¿qué pasa con el value y los módulos constant AngularJS? Solo estoy empezando a usarlos yo mismo, pero me parece que estas son probablemente las mejores opciones aquí.

Nota: a la hora de escribir, Angular 1.3.7 es el último estable, creo que estos fueron agregados en 1.2.0, sin embargo no lo han confirmado con el registro de cambios.

Según la cantidad que necesite definir, es posible que desee crear un archivo separado para ellos. Pero generalmente los defino justo antes del bloque .config() mi aplicación para facilitar el acceso. Debido a que estos siguen siendo módulos efectivamente, deberá confiar en la dependency injection para usarlos, pero se consideran “globales” para su módulo de aplicación.

Por ejemplo:

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

Luego dentro de cualquier controlador:

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

A partir de la pregunta inicial, en realidad parece que aquí se requieren propiedades estáticas, ya sea como mutable (valor) o final (constante). Es más mi opinión personal que otra cosa, pero encuentro que colocar elementos de configuración de tiempo de ejecución en $rootScope vuelve demasiado complicado, demasiado rápido.

 // 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; }]); 

En tu HTML:

 {{config.APP_NAME}} | v{{config.APP_VERSION}} 

$rootScope si me equivoco, pero cuando se publique Angular 2.0 no creo que $rootScope esté disponible. Mi conjetura se basa en el hecho de que $scope se está eliminando. Obviamente, los controladores seguirán existiendo, pero no en la forma ng-controller Piénsese en inyectar controladores en directivas. Como el lanzamiento es inminente, será mejor utilizar los servicios como variables globales si desea un tiempo más fácil para pasar de la versión 1.X a la 2.0.

 localStorage.username = 'blah' 

Si tiene la garantía de estar en un navegador moderno. Aunque sepa que sus valores se convertirán en cadenas.

También tiene la ventaja práctica de estar en la memoria caché entre recargas.

También puede usar la variable de entorno $window para que una variable global declarada fuera de un controlador pueda verificarse dentro de un $watch

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

Por supuesto, el ciclo de resumen es más largo con estos valores globales, por lo que no siempre se actualiza en tiempo real. Necesito investigar sobre ese tiempo de digestión con esta configuración.

Acabo de encontrar otro método por error:

Lo que hice fue declarar una statement de aplicación var db = null y luego la modifiqué en la aplicación.js y luego, cuando app.js a ella en el controller.js , pude acceder a ella sin ningún problema. Puede haber algunos problemas con esto método que no conozco, pero es una buena solución, supongo.

Intenta esto, no $rootScope a inyectar $rootScope en el controlador.

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

Solo puede usarlo en el bloque de ejecución porque el bloque de configuración no le proporcionará el uso de $ rootScope.

También puedes hacer algo como esto …

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