2

EDIT:

This might be a more applicable Question to answer for me as it is more useful How can I watch for changes to localStorage in Angular2?

So I have my main app.component with navbar and and a separate login page. what I want is when they are logged in they can see the menu otherwise they can't. What would be great is if I can add a change to localStorage event. This way I can make one menu to dynamically change on localStorage event.

@Component({
    selector: 'my-app',
    providers: [FORM_PROVIDERS, RoleService, UserService, Login, LoginService],
    inputs: ['loggedIn'],
    directives: [ROUTER_DIRECTIVES, CORE_DIRECTIVES, LoggedInRouterOutlet],
    template: `<body>
                <div *ngIf="loggedIn === true">
                    <nav class="navbar navbar-inverse navbar-top" role="navigation">
                        <div class="container">
                                <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                                    <ul class="nav navbar-nav navbar-right">
                                    <li>
                                        <a (click)="logout()">Logout</a>
                                    </li>
                                    </ul>
                                </div>
                         </div>
                    </nav>
                </div>
                    <div class="container">
                        <router-outlet></router-outlet>
                    </div>
                  </body>`
})
export class AppComponent{

    loggedIn: boolean;

    constructor(public Login: Login){ /*<--This is a component, can I use it in constructor?*/
        Login.loggedIn.subscribe((data) => this.onUserChanged(data));
    }

    onUserChanged(user){
        this.loggedIn = true;
        console.log(this.loggedIn);
    }

    logout(){
        localStorage.removeItem('jwt');
    }

}

My Login.component:

@Component
export class Login{

    jwt: any;
    username: string;
    password: string;
    loggedIn: EventEmitter<boolean>;

    constructor(public _loginService: LoginService, public router: Router){
        this.loggedIn = new EventEmitter();
    }

    submitLogin(username, password){
        let body = {username, password};
        this._loginService.authenticate(body).subscribe(
            response => {
                localStorage.setItem('jwt', response.json_token);
                this.router.navigate(['UserList']);
                this.loggedIn.emit(<boolean>true); /*<---Is this in the wrong place?*/
                console.log(this.loggedIn);
            }
        );

    }
}

My Login.service:

@Injectable()
export class LoginService {

    constructor(public http: Http) {

    }

    authenticate(form_body){
        return this.http.post('/login', JSON.stringify(form_body), {headers: headers})
                .map((response => response.json()));
    }
}

I am sure it is something wrong with my event emitter. I tried to replicate what was already answered in this post Angular2 - 'watch' provider property in multiple components but I just cannot seem to figure out what I am doing wrong.

I'd like something that says if localstorage is set show menu. Thanks!

Community
  • 1
  • 1
Morgan G
  • 3,089
  • 4
  • 18
  • 26

1 Answers1

1

Don't add services (LoginService, ...) to a components providers: list when you want to share it with the whole application. Only add it to

bootstrap(AppComponent, [OtherProviders, LoginService]);

When you add it to a component a new (different) instance is created for this component and it's children than the one other components receive. When a service is only added to bootstrap() the whole application shares the same service instance.

Your service also needs the @Injectable() decorator

@Injectable()
export class Login{

add this also to all other of your services (not strictly necessary if the services doesn't have constructor parameters).

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • Ok I did that but my event-emitter still is not emitting a boolean to my appComponent when I login. It's not doing anything at all actually. So my appComponent never receives a change to my menu. this `Login.loggedIn.subscribe((data) => this.onUserChanged(data));` never receieves anything. – Morgan G Feb 14 '16 at 18:26
  • Did you do that with all related services (not only `LoginService`)? I also updated my answer. – Günter Zöchbauer Feb 14 '16 at 18:28
  • Yeah I did, I think it probably has something to do with me trying to call Login: Login in my constructor from a non-injectable. My problem is without doing that I don't know how to seperate my app out in a way that makes sense. – Morgan G Feb 14 '16 at 18:34
  • Not sure what you mean by "non-injectable" and by "separate my app out". Can you please elaborate what you try to accomplish? – Günter Zöchbauer Feb 14 '16 at 18:35
  • I am using constructor{ Login : Login} on a @ Component and not an @ Injectable I am not sure if that makes any difference. what I mean by "separate my app out" is how to divide up the app to make a separation of concerns. Eitherway my event-emitter is not making it to my other component and I am still unclear why. – Morgan G Feb 14 '16 at 18:39
  • I made some changes to show what my classes are to make it more clear by labelling @ Component and @ Inject before each class. – Morgan G Feb 14 '16 at 18:41
  • Ah, `Login` is a component. But that doesn't change anything. I think it should work. I might have another look later. Have to leave. – Günter Zöchbauer Feb 14 '16 at 18:42
  • Ok thanks, I'll keep trying to figure it out. Sorry about the confusion. – Morgan G Feb 14 '16 at 18:44