Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access key data across entire app in Angular 2 & Ionic 2

What would be the best way to store data that I can access across an entire app in Angular 2 and Ionic 2 - typescript.

For user information my initial thought was to just import the User class in every file its needed, but since all I require from there is a user ID I thought it'd be better to have some kind of config file, maybe the App class - and I could store environment information as well and urls ect.

I actually have no idea what the best practice around this is and couldn't find much on the topic.

like image 993
Dustin Silk Avatar asked Jan 15 '16 16:01

Dustin Silk


3 Answers

One way to do it would be to make class with all the properties that you need and configure as a singleton when you bootstrap the application.

Service:

import {Injectable} from 'angular2/angular2';


@Injectable()
export class Config {

  constructor() {}

  public get USERID(): string {
      return "XCAMPLISHIOUS";
  }

}

Bootstraping:

import {bootstrap} from 'angular2/angular2';
import {TaciIlieApp} from './app/taci-ilie';
import {Config} from './app/services/config/config';

bootstrap(TaciIlieApp, [Config]); // configuring the Config provider here will ensure a single instance is created

Usage:

import {Component, Inject} from 'angular2/angular2';

import {Config} from '../../services/config/config';

@Component({
  selector: 'game',
  templateUrl: 'app/components/game/game.html',
  styleUrls: ['app/components/game/game.css'],
  providers: [],
  directives: [],
})
export class Game {


  constructor(private config: Config) {
      console.log(this.config.USERID);
  }
like image 185
toskv Avatar answered Sep 24 '22 19:09

toskv


In the official Ionic 2 forum I found that you should

Inject it into the @App itself, then import it in the @Page to use it.

This is because Ionic doesn't use the same process as Angular 2 for bootstrapping your app, and the @App decorator doesn't provide the ability to create singleton services that are automatically available to all pages and components in your application; therefore the logical use is to inject your service in both your App.ts and the Page in which you are going to use it... Well, this kinda should be the behavior... in my case (I am working with Ionic 2 beta 5) this doesn't work, if you do that and inject @App and your @Page with your service (both importing them and using the providers array, it will create two separate services, which in my case is not so good because I am setting values for my service in App.ts and retrieving those values in some of my pages. So, if you need Singleton behavior, the way to go for me was to create a singleton service using the ol' gang of four pattern this way..

In your Service...

export class Globals {

//----------------------------------------------------------------------------------------------
// Static (Singleton Implementation) Properties Section:
//----------------------------------------------------------------------------------------------
static instance         : Globals;
static isCreating       : Boolean = false;

//----------------------------------------------------------------------------------------------
// Private Properties Section:
//----------------------------------------------------------------------------------------------
private screenWidth     : number;
private screenHeight    : number;

//----------------------------------------------------------------------------------------------
// Constructor Method Section:
//----------------------------------------------------------------------------------------------
constructor()
{
    if (!Globals.isCreating)
    {
        throw new Error("No se puede llamar a esta clase con 'new' - Utiliza getInstance()");
    }
}


//----------------------------------------------------------------------------------------------
// (Singleton Implementation) getInstance() Method:
//----------------------------------------------------------------------------------------------
static getInstance() : Globals
{
    if (Globals.instance == null)
    {
        Globals.isCreating = true;
        Globals.instance = new Globals();
        Globals.isCreating = false;
    }

    return Globals.instance;
}


//----------------------------------------------------------------------------------------------
// Properties Section (ScreenWidth):
//----------------------------------------------------------------------------------------------
getScreenWidth() : number
{
    return this.screenWidth;
}
//----------------------------------------------------------------------------------------------
setScreenWidth(val) : void
{
    this.screenWidth = val;
}

//----------------------------------------------------------------------------------------------
// Properties Section (ScreenHeight):
//----------------------------------------------------------------------------------------------
getScreenHeight() : number
{
    return this.screenHeight;
}
//----------------------------------------------------------------------------------------------
setScreenHeight(val) : void
{
    this.screenHeight = val;
}}

Then wherever you need to use it...

  1. Import it first

import {Globals} from './services/globals';

  1. Create a private property to hold a reference to your service

globals: Globals;

  1. Since we are not using @Injectable() we should not inject our service in the constructor, however let's add this line to create an instance using the getInstance() method and assign it to our private property.
this.globals = Globals.getInstance();
  1. now you can use your service as a singleton in your code.
ngOnInit()
{
    // Device Dimensions:
    let that : any = this;
    screensize.get().then((result) => {
        setTimeout(()=> {
            that.globals.setScreenWidth(result.width);
            that.globals.setScreenHeight(result.height);
        },50);
    },
    (error) => {
        // Do Nothing yet...
    });
}

I have been a little verbose in explaining exactly how I did it because I know that like me, there are lots of developers still getting a grip in Ionic 2 and Angular 2, it costs tons of hours to learn a platform and with issues like this you can literally spend days trying to figure out things, I hope this solution work for you and btw, I know that it may be obsolete by now since Ionic 2 Beta 6 was just released, my advise is for you to test both solutions, first the one in the forum and if that one doesn't work, this one worked for me and I hope it may make things work for you as well.

like image 40
Will de la Vega Avatar answered Sep 24 '22 19:09

Will de la Vega


Using a provider to hold global data is working for me in Ionic 2 beta 6, and I believe it is the recommended practice in Angular 2.

Generate a provider from the command line: ionic g provider GlobalService Notice how the generated service is decorated with @Injectable

Inject your service in the @App class; you do this by declaring it in the providers array:

  @App({
        templateUrl: 'build/app.html',
              providers: [GlobalService] ,
              config: {} // http://ionicframework.com/docs/v2/api/config/Config/
            })

This will create an single instance of your provider that is accesible on every page. Wherever you need to use it, do not declare in the providers array, but on the constructor of the Page:

@Page({
        templateUrl: 'build/pages/new-page/new-page.html',
      })
      export class NewPage{

       constructor(public globalService: GlobalService) {
    }

    someFunction(){
    this.globalService.someGlobalFunction();
    }
like image 40
Manu Valdés Avatar answered Sep 22 '22 19:09

Manu Valdés