1

Hi I am using the new alpha component router of angularjs2 https://angular.io/docs/ts/latest/guide/router.html

I have a modal that authenticate a user then creates a JWT in localstorage which holds the user's needed info.

My problem is that if the user is looking on the /home path there are stuff there that only visible to logged-in users, but after he log in through the modal he has to refresh the page so the components will refresh and show the correct logged-in information

Is there a way to tell angular2 to refresh all the components on the current path? like a page reload but without really reloading the whole page (I dont want to just hit the refresh button for the user)

Thanks in advance

EDIT: maybe there is a feature to FORCE REDIRECT when I try to redirect into a route I am already in?

EDIT2: Trying with observables

@Injectable()
export class UserService {
  private loggedInObservable;

    constructor(private http: Http) {
        this.loggedInObservable = Observable.of(this.checkIsLoggedIn());
    }

    checkIsLoggedIn() {
        let isLoggedIn = false;
        try {
            isLoggedIn = tokenNotExpired();
        } catch(e) {

        }
        console.log('returning:', isLoggedIn);
        return isLoggedIn;
    }


    login(model, cbSuccess=null, cbError=null, cbAlways=null) {
        serverPost(this, '/api/users/login', model, cbSuccess, cbError, cbAlways, (data)=> {
            localStorage.setItem("id_token", data.id_token);
            this.loggedInObservable.map((val) => console.log('HELLO?'));
        });
    }

    isLoggedInObservable() {
        return this.loggedInObservable;
    }
}

the map does NOTHING at all (the 'HELLO?' isn't being displayed), although the observer has a value the map function does not call anything.

Using the observer:

import {Component, OnInit, OnDestroy} from '@angular/core';
import {UserService} from '../../services/userservice';

@Component({
  selector: 'test-thing',
  template: require('./test-thing.html'),
  styles: [require('./test-thing.scss')],
  providers: [],
  directives: [],
  pipes: []
})
export class TestThing implements OnInit, OnDestroy{
    private isLoggedIn = false;
    private sub: any;

    constructor(private userService: UserService) {

    };

    ngOnInit() {
      this.sub = this.userService.isLoggedInObservable().subscribe(loggedIn => {
        this.isLoggedIn = loggedIn;
      });
    }

    ngOnDestroy() {
      this.sub.unsubscribe();
    }
}

The initial value is working as intended but when I try to change the value after a successful login (with map) nothing happens, nothing at all.

BlackICE
  • 8,816
  • 3
  • 53
  • 91
kfir124
  • 1,286
  • 4
  • 14
  • 27
  • To update logged-in information it shouldn't be necessary to reload everything. If you update the data, the bound view will update because of Angular change detection. – Günter Zöchbauer Jun 22 '16 at 17:24
  • @GünterZöchbauer The problem is that I set `isLogged=x` in the `ngOnInit` so the variable is passed by value and I have no way to change it when a different modal sets the localStorage to hold the session. Do you mean to use Observables? I would rather avoid forcing all the components to subscribe to a change but I guess it can work like that – kfir124 Jun 23 '16 at 11:31
  • I would use an observable. It's a much cleaner solution. You can subscribe to router parameter changes and the whole application gets updated automatically if you notify about the change at one place. – Günter Zöchbauer Jun 23 '16 at 11:46
  • @GünterZöchbauer I dont want to reflect a change in the url when you are logged in or not, can I create an observable in a service? is there a way to automatically unsubscribing from an observable on NgDestroy or I must manually set it up for each component? – kfir124 Jun 23 '16 at 12:19
  • If you subscribe manually you need to unsubscribe manually. If you subscribe only in the template using the `| async` pipe, then you don't need to unsubscribe. – Günter Zöchbauer Jun 23 '16 at 13:56
  • @GünterZöchbauer please look at my EDIT2 I'm trying to create an observable of 1 boolean value that will change depanding if the user is logged in or not, the problem is that there is 5% documentation about observable with 1 value or observable at all, I tried to use map to change the value of the observable to true if the user is logged in but seems like the map does not call my function at all. – kfir124 Jun 23 '16 at 14:09
  • What is `serverPost()`. You need to `.subscribe()` somewhere. `Observable`s are lazy. Without subscribing they aren't supposed to do anything. – Günter Zöchbauer Jun 23 '16 at 14:59
  • @GünterZöchbauer I've added serverPost and an example of where I subscribe to (the initial value is wokring but it doesnt detect any changes and the map function does nothing when I call it from the login() function) I want to add that the localStorage is getting set so the function is getting called, its just the map function that ignores me – kfir124 Jun 23 '16 at 15:11
  • Change it to `subscribe` `this.loggedInObservable.subscribe((val) => console.log('HELLO?'))` – Günter Zöchbauer Jun 23 '16 at 17:36
  • @GünterZöchbauer thanks it works but the `TestThing` component doesn't receive the update to value of isLoggedIn `this.loggedInObservable.subscribe((val) => this.checkIsLoggedIn());` – kfir124 Jun 23 '16 at 18:20

1 Answers1

5

Ok so seems what I needed is a BehaviorSubject since you can push values into it,subscribe to it to get changes and it projects the last value it got the first time you subscribe to it which is exactly what I need.

My code is now as follows:
userservice.ts

import {Injectable} from '@angular/core';
import {Http} from '@angular/http';
import {serverPost} from '../../functions';
import {BehaviorSubject} from 'rxjs/BehaviorSubject'
import {tokenNotExpired} from 'angular2-jwt';

@Injectable()
export class UserService {
    private isLoggedInSubject: BehaviorSubject<boolean>;

    constructor(private http: Http) {
        this.isLoggedInSubject = new BehaviorSubject(this.checkIsLoggedIn());
    }

    get loggedInObservable() {
        return this.isLoggedInSubject.asObservable();
    }

    checkIsLoggedIn() {
        let isLoggedIn = false;
        try {
            isLoggedIn = tokenNotExpired();
        } catch(e) {

        }
        return isLoggedIn;
    }

    signUp(model, cbSuccess=null, cbError=null, cbAlways=null) {
        serverPost(this, '/api/users', model, cbSuccess, cbError, cbAlways, (data)=> {
            localStorage.setItem("id_token", data.id_token);
            this.isLoggedInSubject.next(this.checkIsLoggedIn());
        });
    }

    login(model, cbSuccess=null, cbError=null, cbAlways=null) {
        serverPost(this, '/api/users/login', model, cbSuccess, cbError, cbAlways, (data)=> {
            localStorage.setItem("id_token", data.id_token);
            this.isLoggedInSubject.next(this.checkIsLoggedIn());
        });
    }
}

And this is how I use it in a component:

export class TestComponent implements OnInit, OnDestroy{
    private isLoggedIn = false;
    private loginSub;

    constructor(private userService: UserService) {

    };

    ngOnInit() {
      this.loginSub = this.userService.loggedInObservable.subscribe(val => {
        this.isLoggedIn = val;
      });
    }

    ngOnDestroy() {
      this.loginSub.unsubscribe();
    }

}

This setup works perfectly for my needs.

kfir124
  • 1,286
  • 4
  • 14
  • 27