Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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-outlets 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

like image 674
Robin van Breukelen Avatar asked Nov 23 '16 14:11

Robin van Breukelen


1 Answers

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.

like image 122
Robin van Breukelen Avatar answered Sep 18 '22 23:09

Robin van Breukelen