How to define global variables in Angular 2 in a way that I can use them for property binding in templates?

In my Angular 2 (beta 14) application I need to keep track of user login status in order to hide/display certain elements.

The issue I’m getting is that property binding is not working the way I did as follows.

I created a class to store and update global variables:

app-global.ts

 import {Injectable} from "angular2/core";

 @Injectable() export class AppGlobals {
   // use this property for property binding
   public isUserLoggedIn: boolean = false;

   setLoginStatus(isLoggedIn){
       this.isUserLoggedIn = isLoggedIn;
   }

   getLoginStatus(){
       return this.isUserLoggedIn;
   } }

In the login component I import AppGlobals

export class LoginComponent {
    constructor(private _appGlobals: AppGlobals) { }

and set login state by

this._appGlobals.setLoginStatus(true);

In another component I inject AppGlobals as I do in LoginComponent

I define a class (component)’s property

isLoggedIn: boolean = this._appGlobals.isUserLoggedIn; // I also tried by using the getter instead of the public property (see above)

which I then use in the component’s template to show/hide a certain element:

<!-- here I also tried with {{!isLoggedIn}} but results in a syntax error whereas using [(hidden)] instead of [hidden] changes nothing -->
<div id="some-element" [hidden] = "!isLoggedIn">

Finally, the binding works but there is no update (this component is part of AppComponent template and shown in every page) when another component (e.g. LoginComponent) sets the login status.

EDIT I tried to apply Gunter’s answer but I get the following errors:

app/app-globals.ts(10,54): error TS2346: Supplied parameters do not match any signature of call target.
app/app-globals.ts(13,29): error TS2339: Property 'emit' does not exist on type 'BehaviorSubject<boolean>'.

Error at line 10 comes from [SOLVED]

public isUserLoggedIn:BehaviorSubject = new BehaviorSubject().startWith(false);

and it’s apparently caused by BehaviorSubject expecting 1 parameter

Error at line 13 comes from

this.isUserLoggedIn.emit(isLoggedIn);

and it’s apparently cause by a non-existing emit method.

Also, I don’t understand how shall I use AppGlobals so that the property binding auto updates in another component (see last example before EDIT)

Further, in LoginComponent I replaced isLoggedIn boolean type with BehaviorSubject because isUserLoggedIn has type BehaviorSubject in AppGlobals

but

this._appGlobals.isUserLoggedIn.subscribe(value => this.isLoggedIn = value);

returns a TypeError:

Assigned expression type boolean is not assignable to type BehaviorSubject

2
Leave a Reply

avatar
2 Comment threads
0 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
1 Comment authors
Jason Recent comment authors
  Subscribe  
newest oldest most voted
Notify of
Jason
Guest
isLoggedIn: boolean = this._appGlobals.isUserLoggedIn;

is a one-time action that copies the value at the time when this line is executed. If you want subsequent changes to be propagated use observables

import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/share';
import 'rxjs/add/operator/startWith';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';

@Injectable() 
export class AppGlobals {
// use this property for property binding
  public isUserLoggedIn:BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);

  setLoginStatus(isLoggedIn){
   this.isUserLoggedIn.next(isLoggedIn);
  }
}

and use it like:

export class LoginComponent {
    constructor(private _appGlobals: AppGlobals) {
  this._appGlobals.isUserLoggedIn.subscribe(value => this.isLoggedIn = value);
}

See also https://stackoverflow.com/a/35568924/217408

Jason
Guest

had a similar need, ended up implementing this via simple getter – and it binds the property in the template (–> changes propagate). less code.

you can set the global var either directly or implement setters/getters in the Globals class.

globals.ts

export class Globals{
    public static server_call_in_progress:boolean = true;
}

app.component.ts

import {Globals} from "./shared/globals";    
export class AppComponent{  
    constructor(){}
    ngOnInit(){}

    get server_call_in_progress(){
        return Globals.server_call_in_progress;
    }
}

app.component.html

<div *ngIf="server_call_in_progress">
    <div class="loader"></div>
</div>