Variables globales en AngularJS


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

Asumo que esta no es la forma correcta de declarar e inicializar variables globales, bueno, no es realmente global, por lo que mi pregunta es cuál es la forma correcta y ¿hay buenos ejemplos en torno a ese trabajo con la versión actual de angular?

Author: Damjan Pavlica, 2012-08-13

12 answers

Tienes básicamente 2 opciones para variables "globales":

$rootScope es un 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 simplemente puede inyectarlo en cualquier controlador y cambiar los valores en este ámbito. Podría ser conveniente, pero tiene todos los problemas de variables globales.

Los servicios son singletons que puede inyectar a cualquier controlador y exponer sus valores en el ámbito de un controlador. Los servicios, al ser singletons, siguen siendo "globales", pero tienes mucho mejor control sobre dónde se usan y 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 /

 474
Author: pkozlowski.opensource,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-10 06:28:23

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

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

Luego úsalo en un controlador como este:

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

Lo mismo se puede lograr usando un Proveedor, Fábrica o Servicio, ya que son "solo azúcar sintáctico encima de una receta de proveedor", pero usando Valor logrará lo que desea con una sintaxis mínima.

La otra opción es usar $rootScope, pero no es realmente una opción porque no deberías usarlo por las mismas razones por las que no deberías usar variables globales en otros idiomas. Es aconsejado que se use con moderación.

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


Si desea modificar este valor y mantenerlo en todos sus controladores, use un objeto y modifique las propiedades teniendo en cuenta Javascript is pass by "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

 90
Author: Dean Or,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:44

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 que funciona: http://jsfiddle.net/natefriedman/3XT3F/1 /

 34
Author: NateFriedman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-01 16:36:31

En el interés de añadir otra idea al pool wiki, pero qué pasa con AngularJS' value y constant ¿módulos? Solo estoy empezando a usarlos yo mismo, pero me parece que estas son probablemente las mejores opciones aquí.

Nota: en el momento de escribir esto, Angular 1.3.7 es el último estable, creo que estos fueron añadidos en 1.2.0, aunque no lo he confirmado con el registro de cambios.

Dependiendo de cuántos necesite definir, es posible que desee crear un archivo separado para ellos. Pero generalmente defino estos justo antes del bloque .config() de mi aplicación para facilitar el acceso. Debido a que estos todavía son módulos de manera efectiva, deberá confiar en la inyección de dependencias 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
  })

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

 24
Author: ZaLiTHkA,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-19 19:37:18
// 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 su HTML:

<span ng-controller="GlobalVarController">{{config.APP_NAME}} | v{{config.APP_VERSION}}</span>
 19
Author: CelticParser,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-28 22:55:16

Por favor, corríjame si me equivoco, pero cuando se lance Angular 2.0 no creo que$rootScope esté disponible. Mi conjetura se basa en el hecho de que $scope está siendo eliminado. Obviamente, los controladores seguirán existiendo, pero no de la manera ng-controller.Piense en inyectar controladores en las directivas en su lugar. Como el lanzamiento viene inminente, será mejor usar servicios como variables globales si desea un momento más fácil para cambiar de versión 1.X a 2.0.

 6
Author: jason328,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-22 19:31:36
localStorage.username = 'blah'

Si está garantizado que estará en un navegador moderno. Aunque sepa que sus valores se convertirán en cadenas.

También tiene el práctico beneficio de ser almacenado en caché entre recargas.

 6
Author: Kevin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-20 18:43:01

También puede usar la variable de entorno $window para que una variable global declare 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 lo tanto, el ciclo de compendio es más largo con estos valores globales, por lo que no siempre se actualiza en tiempo real. Necesito investigar en ese tiempo de resumen con esta configuración.

 1
Author: Megaman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-20 14:12:51

Acabo de encontrar otro método por error :

Lo que hice fue declarar una var db = null declaración de la aplicación anterior y luego modificarla en el app.js luego cuando accedí a ella en el controller.js Pude acceder a él sin ningún problema.Puede haber algunos problemas con este método que no soy consciente de, pero es una buena solución, supongo.

 0
Author: Black Mamba,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-12 10:57:53

Pruebe esto, no forzará a inyectar $rootScope en el controlador.

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

Solo puede usarlo en run block porque config block no le proporcionará usar el servicio de $rootScope.

 0
Author: Rahul Murari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-29 06:51:52

En realidad es bastante fácil. (Si estás usando Angular 2 + de todos modos.)

Simplemente agregue

declare var myGlobalVarName;

En algún lugar en la parte superior de su archivo de componente (como después de las instrucciones "import"), y podrá acceder a "myGlobalVarName" en cualquier lugar dentro de su componente.

 0
Author: Andy Corman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-10-09 22:13:49

También puedes hacer algo como esto ..

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

function MyCtrl2($scope) {
    var name = $rootScope.$root.name;
}
 -2
Author: pkdkk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-31 12:36:25