Global variables on ionic 2

How can i use global variables on ionic 2?
Which can be access anywhere between pages and the views like on ionic 1.

2 Likes

declare var socket: any;

import {App,Page, IonicApp, Platform, Storage, SqlStorage} from 'ionic/ionic';
@App({
  templateUrl: 'build/app.html'
})

Edit app.js .
declare socket var on top . You can access “socket” variable in other pages .

This is the only way to declare global variable? if I have 10 global var of different types then I have to declare all variable one after another at app.ts?

declare var socket: any;
declare var push: any;
declare var username: any;
import {App,Page, IonicApp, Platform, Storage, SqlStorage} from ‘ionic/ionic’;
@App({
templateUrl: ‘build/app.html’
})

I think it depends on what you want to do really but take a look at the Conference app here and have a look at how the favourites variable is maintained in there with getters and setters etc and shared across multiple components using the user-data provider.

1 Like

Well… if using webpack you could declare them from the webpack.config.js but then you would be tied to webpack until you declare those variables in your code, also it’s not a recommended way of doing it since those variables definition would be in the config of the build process and not in your source code, which makes way harder to understand the code since you can’t tell where the hell those variables come from unless you’re the one that made the variables, tough is a good step for polyfills and libraries that need global scope like Chart.js.

In Ionic 2, we have ES6 modules, and having global variables isn’t really recommended. In fact, it’s big anti-pattern with modules

@richardshergold is pointing you in the right direction. Having a dedicated data-store class instead is what you should be doing. This keeps things nice and separated and you can reason about where things are coming from.

1 Like

Hi am really getting an headache on trying to understand how global variable works in ionic 2 … or how we achieve the same thing.

I read on stackoverflow that some suggest different ways becuz Angular 2 syntax is somehow changing recently, I also read, some mention BehaviorSubject… but I dun understand how it works… or does it work in ionic 2.

I come to realise there’s nothing like $rootScope anymore in ionic2, but I still cant manage to understand how.

  1. Say, I was trying to use ngSwitch to cater an app with mutliple language.
  2. I register a service to detect User Language on default (while allowing them to change it in a dropdown menu).
  3. in ionic 1 I just do the detection at the beginning and store it to a variable in the rootScope, users may change and alter the variable.
  4. ngSwitch will watch the variable and switch language content (for some reason my users need to be able to switch the language anytime quickly).

so… how do I do this in ionic2? declaring variable in the app.ts doesnt work… I tried… :disappointed_relieved:

Hi am really getting an headache on trying to understand how global variable works in ionic 2 … or how we achieve the same thing.

I read on stackoverflow that some suggest different ways becuz Angular 2 syntax is somehow changing recently, I also read, some mention BehaviorSubject… but I dun understand how it works… or does it work in ionic 2.

I come to realise there’s nothing like $rootScope anymore in ionic2, but I still cant manage to understand how.

  1. Say, I was trying to use ngSwitch to cater an app with mutliple language.
  2. I register a service to detect User Language on default (while allowing them to change it in a dropdown menu).
  3. in ionic 1 I just do the detection at the beginning and store it to a variable in the rootScope, users may change and alter the variable.
  4. ngSwitch will watch the variable and switch language content (for some reason my users need to be able to switch the language anytime quickly).

so… how do I do this in ionic2? declaring variable in the app.ts doesnt work… I tried… :disappointed_relieved:

Look at ng2-translate. There is an Ionic sample in the README.

thanks @rapropos I will try to make sense of that.

It looks promising on creating some mutli-language app.
However I am using multiple JSON to load some sort of complicated ancient text content to the view…
It is hard to explain, but it seems a bit different from just switching between language.:sob:
I really need NgSwitch to get working to solve the problem in the simplest manner. :thinking:

So I really really really… want to know how to get it working, to store and change a variable and bind it with content.

@richardshergold covered that upthread with links to exactly where to look in the conference app.

How about storing your globals in a singleton class? As in:

  • make a module for your globals, have it contain one class that has all the “globals” you need.
  • use the class as a singleton by decorating it with @Injectable and including it in app.ts and in its ionicBootstrap() call
  • include the class anywhere you need a global

Done!

Thanks @doron
I was sort of trying to achieve it in a similar way by setting up a “globals” class/service with Injectable.

Then, I face a problem, while the variables are being updated, the changes were not known real-time by other component. I ended up using an “emit” function to get it done by triggering an event.

Not sure if this is the proper way of doing it, but it worked.

Yes, @ultradryan, that’s exactly what I was suggesting. I also used this (injectable provider class) solution and had the same problem - that some variables were not being detected as changed.

That turned out to be related to zone.js and angular2 change detection.

One (probably terrible) hack that solved things and always worked for me was to set the variable inside a setTimeout() (or similar) call because that triggers the angular2 change detection. So I did:

In the provider, injectable class that provides a variable’s value to another:

instead of this:

this.memberVariable = value;

i had this:

setTimeout(this.memberVariable = value);

and the change-detection issue went away.

I think this is a hack and at some point I’ll look more into improving on it because I dislike hacks, but it works.

I used this method for access to host variable via provider e.g.

in app.ts top

declare var host : ‘http://xxx’ ;

in provider class :
this.http.get(host+’/api/r/lst’)

But : TypeScript error: path Error TS2304: Cannot find name ‘host’.

@mhartington @richardshergold can you help us (newbies) create ‘best practice’ once and for all to manage global variables in ionic 2? (I know I’m bumping the thread but it’s worth it).

I checked the Conference App as suggested by @richardshergold and looked up the “favorites” variable (not favourites you made a typo :wink: ). And there seem to be a user-data provider in the user-data.ts file.

So I did my own provider:

global-vars.ts:

import { Injectable } from '@angular/core';
import { Events } from 'ionic-angular';
import { Storage } from '@ionic/storage';

  @Injectable()
  export class GlobalVars {

  	_vars: Array<{name: string, value: any}>;

  	constructor(
  		public events: Events,
  		public storage: Storage,
	) {
  		console.log('Hello GlobalVars Provider');
  	}

  	varExist(varName: string): boolean {
   		return (this._vars.indexOf(varName) > -1);
  	};

  	addGlobalVar(varName: string, value: any): void {
  		this._vars.push({
		  name: varName,
		  value: value
		});
  	};

  	removeGlobalVar(varName: string): void {
  		let index = this._vars.indexOf(varName);
  		if (index > -1) {
  			this._vars.splice(index, 1);
  		}
  	};

  }

and in a component,
weightlevel.ts:

import { Component } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { ComparePage } from '../compare/compare';
import { ViewChild } from '@angular/core';
import { Slides } from 'ionic-angular';
import { LocalStorageService } from 'angular-2-local-storage';
import { GlobalVars } from '../../providers/global-vars';

@Component({
    selector: 'page-weightlevel',
    templateUrl: 'weightlevel.html'
})
export class WeightlevelPage {

    name: string;

    constructor(
        public navCtrl: NavController,
        public navParams: NavParams,
        private localStorageService: LocalStorageService,
        public globalVars: GlobalVars,
    ) {
        console.log("Executing Weightlevel.ts");
        this.name = 'Max';
        this.globalVars.addGlobalVar("isWebIntegration", false);
    }

    @ViewChild(Slides) slides: Slides;

    ionViewDidLoad() {
        console.log('ionViewDidLoad WeightlevelPage');
    }

    goToSlide() {
        this.slides.slideTo(2, 500);
    }
}

Can you help me finish this code? It’s not working for now.

Thanks

I think this approach is overly generic, and loses you lots of important compile-time checking, IDE assistance, and self-documentation. If you have a global isWebIntegration boolean, say so. Explicitly put isWebIntegration: boolean in your provider (or expose something that provides a Promise<boolean> if you wish it to be seamlessly integrated with backing storage).

1 Like

I am not sure I get what you say. Can you code it ?

Obviously there are many different options depending on design decisions, but here’s one:

@Injectable()
export class AppContext {
  ready: Promise<any>;
  private _isWebIntegration: boolean;

  constructor(private _storage: Storage) {
    this.ready = Promise.all([
      this._storage.get('isWebIntegration').then((wip) => this._isWebIntegration = wip),
      // &c &c for other similar stuff
    ]);
  }

  // don't call any of these until this.ready resolves

  isWebIntegration(): boolean {
    return this._isWebIntegration;
  }

  setWebIntegration(wip: boolean): Promise<any> {
    this._isWebIntegration = wip;
    return this._storage.set('isWebIntegration', wip);
  }
}
1 Like