9
votes

I wanted to know if you guys now a way to have the @Input + ngOnChanges() combination or something doing the same inside a component in .

Basically, I have set a logged: boolean variable in my AppComponent and in my template I have :

<router-outlet></router-outlet>
<login [logged]="logged"></login>

What I want is to be able to watch that logged variable inside a component in the router-outlet so I make stuff here only when logged is as set as true.

I've tried to put <router-outlet [logged]="logged"></router-outlet> but that doesn't work, and using a variable in a service seems not to fit the ngOnChanges() watch.

Has anyone an idea ? Thanks !

2
Components added by the router can't participate in binding. You need to use a shared service. See angular.io/docs/ts/latest/cookbook/…Günter Zöchbauer
Yeah I know that way but I can't do it that way as I must "watch" the variable. I need my component in the router to wait for the user to be logged. I have a logged variable in the LoginService I can access everywhere but I don't know how to wait for him to be true.Guigui
Then use observables - also demonstrated in the tutorial linked above.Günter Zöchbauer
Angular 2 can't do things you can do with route to components using ui-router in Angular 1.5+ :(Merritt
How about using a service and making the logged property an observable so that other components can subscribe to it and react to changes. If I remember correctly, there is a way to write an observable such that when something subscribes to it, they receive the last data pushed into the stream.Alex Florin

2 Answers

2
votes

Create a service that has an observable to subscribe to

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { ReplaySubject } from 'rxjs/ReplaySubject';

@Injectable()
export class UserSessionService {

  private _loggedIn: ReplaySubject<boolean> = new ReplaySubject<boolean>();

  public logUserIn() {
    this._loggedIn.next( true );
  }

  public logUserOut() {
    this._loggedIn.next( false );
  }

  public getUserLoggedInObs(): Observable<boolean> {
    return this._loggedIn.asObservable();
  }

}

Add the service to a parent module (be careful if adding it to multiple modules as you may get different instances of this service with different loggedIn values)

import { NgModule } from '@angular/core';
import { UserSessionService } from 'wherever/service/is/located';

@NgModule({
  providers: [ UserSessionService ]
})

export class AppModule { }

In your controller do something like

public userLoggedInObs: Observable<boolean>;
constructor( private userSessionService: UserSessionService ) {
  this.userLoggedInObs = userSessionService.getUserLoggedInObs()
}

The in your View you can add

<div *ngIf="userLoggedInObs | async">
  User is logged in
</div>
<div *ngIf="!(userLoggedInObs | async)">
  User isn't logged in
</div>

When you call the service it will broadcast to all components currently subscribed to it, which will then live update.

2
votes

Easiest way I would say is to use a service and add this service to your child

@Injectable() 
export class LoginService {
    private logged:boolean;

    setlogged(data:boolean) {
        this.logged = data;
    }

    isLogged() {
        return this.logged;
    }

OR use localstorage

    set isLogged(value: boolean) {
        localStorage.setItem('logged', value);
    }

    get isLogged(): boolean {
        return <boolean> localStorage.getItem('logged'));
    }
}

In your component:

constructor(private loginService:LoginService) {}
logged: boolean;
ngOnInit() {
    this.logged = true;
    // variable:
    this.loginService.setLogged(logged);
    // Localstorage:
    localStorage.setItem('logged', logged);
}

In your child component:

logged: boolean;
constructor(loginService:LoginService) {
    // variable:
    this.logged = this.loginService.isLogged();
    // Localstorage:
    this.logged = this.loginService.isLogged;
}