Robin van Breukelen Robin van Breukelen - 4 days ago 5
Javascript Question

Angular 2 - Content not loading in router outlet

I'm still pretty new to Angular 2, hopefully you guys can help me out.

I have a fairly simple app, there's a login page, after successful login the user is directed to a page with a sidemenu. The login screen doesn't have this sidemenu. When the user logs out he is directed to the login page again.

The problem is that after login the sidemenu becomes visible but the other content is only visible after a refresh. Same thing for logout, after logout the page is blank, only after refresh the content (login page) is displayed. I'm probably doing something wrong but even after looking at other questions I can't figure it out.

Here's my routing:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { ProfileComponent } from './profile-component/profile-component.component'
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';
import { LoginComponent } from './login/login.component';
import { LoggedInGuard } from './logged-in/logged-in.guard';

const appRoutes: Routes = [
{path: 'profile', component: ProfileComponent, canActivate: [LoggedInGuard]},
{path: 'login', component: LoginComponent},
{path: '', component: LoginComponent},
{path: '**', component: PageNotFoundComponent},
];

@NgModule({
imports: [
RouterModule.forRoot(appRoutes)
],
exports: [
RouterModule
]
})
export class AppRoutingModule {
}


The
LoginComponent
:

import {Component, OnInit} from '@angular/core';
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
import {LoginService} from '../login-service/login-service.service';
import {Router} from '@angular/router';


@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss'],
providers: [ LoginService ]
})
export class LoginComponent implements OnInit {

loginForm: FormGroup;
error: String;

constructor(private formBuilder: FormBuilder,
private loginService: LoginService,
private router: Router) {
}


ngOnInit() {
if (this.loginService.isLoggedIn()) {
this.router.navigate(['/profile']);
}
this.loginForm = this.formBuilder.group({
username: ['', Validators.required],
password: ['', Validators.required]
});
}

login(): void {
let self = this;
this.loginService.login(this.loginForm.value.username, this.loginForm.value.password).subscribe(function (result) {
if (result) {
self.router.navigate(['/profile']);
}

}, function (error) {
self.error = 'Invalid';
});
}
}


The
AppComponent
HTML looks like this:

<md-toolbar color="primary" *ngIf="isLoggedIn()">
<span>Sporter volgsysteem</span>
</md-toolbar>

<md-sidenav-layout *ngIf="isLoggedIn()">
<md-sidenav #start mode="side" [opened]="true">
<a routerLink="/add" routerLinkActive="active" md-button color="primary" disabled="false"><md-icon class="icon">add</md-icon><span class="nav-item">Toevoegen</span></a>
<a routerLink="/compare" routerLinkActive="active" md-button color="primary"><md-icon class="icon">swap_horiz</md-icon><span class="nav-item">Vergelijken</span></a>
<a routerLink="/search" routerLinkActive="active" md-button color="primary"><md-icon class="icon">search</md-icon><span class="nav-item">Zoeken</span></a>
<a routerLink="/profile" routerLinkActive="active" md-button color="primary"><md-icon class="icon">account_box</md-icon><span class="nav-item">Profiel</span></a>
<a routerLink="/feedback" routerLinkActive="active" md-button color="primary"><md-icon class="icon">feedback</md-icon><span class="nav-item">Feedback</span></a>
<a routerLink="/faq" routerLinkActive="active" md-button color="primary"><md-icon class="icon">info</md-icon><span class="nav-item">FAQ</span></a>

<div class="spacer"></div>

<a md-button color="primary" routerLink="/login" (click)="logout()"><md-icon class="icon">exit_to_app</md-icon><span class="nav-item">Uitloggen</span></a>
</md-sidenav>


<router-outlet></router-outlet>
</md-sidenav-layout>


<router-outlet *ngIf="!isLoggedIn()"></router-outlet>


AppComponent
:

import {Component} from '@angular/core';
import {LoginService} from "./login-service/login-service.service";
import {Router } from '@angular/router'


@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
providers: []
})
export class AppComponent {

constructor(private loginService : LoginService,
private router: Router) {
}

logout() {
this.loginService.logout();
this.router.navigate(['/login']);
}

isLoggedIn() {
return this.loginService.isLoggedIn();
}

}


So why isn't the content of the
ProfileComponent
displaying after login, and why isn't the login page displaying after logout, but both display when you refresh?

Update

Most suggested that it is due to multiple unnamed
router-outlet
s so to verify that I removed one of the outlets and show the sidemenu layout all the time. For testing purposes of course. That doesn't solve the problem, it gives me the same behaviour: the profile content is only loaded after refresh.

Update 2
I'm guessing this is related to using
*ngIf
to display the
router-outlet

Answer

Following the comments above from @bhetzie and @jaime-torres and my own hypothesis I investigated further. It turns out that the problem is indeed with the double router-outlet.

My solution was to extract a LoginModule module and then in that module redirect to the login page. In all other cases I route to yet another module called SvsModule which displays the logged in content with a side nav structure.

So the SvsModule has the following routing:

RouterModule.forChild([
  {path: 'svs', component: ProfileComponent, canActivate:[LoggedInGuard]},
  {path: 'svs/profile', component: ProfileComponent, canActivate:[LoggedInGuard]}
])

And the ProfileComponent uses the following HTML:

<md-sidenav-layout>
  <md-sidenav #start mode="side" [opened]="true">
    <md-nav-list>
      <a routerLink="/add" routerLinkActive="active" md-button color="primary" disabled="false">
        <md-icon class="icon">add</md-icon>
        <span class="nav-item">Toevoegen</span>
      </a>
      <a routerLink="/compare" routerLinkActive="active" md-button color="primary">
        <md-icon class="icon">swap_horiz</md-icon>
        <span class="nav-item">Vergelijken</span>
      </a>
      <a routerLink="/search" routerLinkActive="active" md-button color="primary">
        <md-icon class="icon">search</md-icon>
        <span class="nav-item">Zoeken</span>
      </a>
      <a routerLink="/profile" routerLinkActive="active" md-button color="primary">
        <md-icon class="icon">account_box</md-icon>
        <span class="nav-item">Profiel</span>
      </a>
      <a routerLink="/feedback" routerLinkActive="active" md-button color="primary">
        <md-icon class="icon">feedback</md-icon>
        <span class="nav-item">Feedback</span>
      </a>
      <a routerLink="/faq" routerLinkActive="active" md-button color="primary">
        <md-icon class="icon">info</md-icon>
        <span class="nav-item">FAQ</span>
      </a>

      <div class="spacer"></div>

      <a md-button color="primary" routerLink="/login" (click)="logout()">
        <md-icon class="icon">exit_to_app</md-icon>
        <span class="nav-item">Uitloggen</span></a>
    </md-nav-list>

  </md-sidenav>
  <router-outlet></router-outlet>

</md-sidenav-layout>

I will accept this as the answer, but thanks to aforementioned users to help me on my path.

Comments