2016-11-23 5 views
3

Ich bin noch ziemlich neu in Angular 2, hoffentlich könnt ihr mir helfen.Angular 2 - Inhalt wird nicht in Router Outlet geladen

Ich habe eine ziemlich einfache App, es gibt eine Login-Seite, nach erfolgreicher Anmeldung wird der Benutzer auf eine Seite mit einem Sidemenu geleitet. Der Anmeldebildschirm hat dieses Seitenmenü nicht. Wenn sich der Benutzer abmeldet, wird er erneut zur Anmeldeseite geleitet.

Das Problem ist, dass nach dem Login das Sidemenu sichtbar wird, aber der andere Inhalt nur nach einer Aktualisierung sichtbar ist. Gleiches gilt für die Abmeldung, nach dem Abmelden ist die Seite leer, erst nach dem Refresh wird der Inhalt (Login-Seite) angezeigt. Ich mache wahrscheinlich etwas falsch, aber selbst nachdem ich andere Fragen untersucht habe, kann ich es nicht herausfinden.

Hier ist meine Route:

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 { 
} 

Die 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'; 
    }); 
    } 
} 

Die AppComponent HTML sieht wie folgt aus:

<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(); 
    } 

} 

Warum ist nicht der Inhalt der ProfileComponent nach der Anmeldung angezeigt, und warum wird nicht die Anmeldeseite nach dem Abmelden angezeigt, aber beide angezeigt, wenn Sie aktualisieren?

aktualisieren

meisten vorgeschlagen, dass es auf mehrere ungenannte router-outlet gebührt s so zu überprüfen, ob ich einen der Auslässe entfernt und das Layout sidemenu die ganze Zeit zeigen. Zu Testzwecken natürlich. Das löst das Problem nicht, es gibt mir das gleiche Verhalten: Der Profilinhalt wird erst nach dem Refresh geladen.

Update 2 ich dies zu raten, ist im Zusammenhang mit dem *ngIfrouter-outlet

+0

Ihr 'AppComponent' hat 2' 'und beide haben keinen' name = "xxx" '. Es ist nur ein unbenannter Router-Ausgang pro Route erlaubt. –

+0

@ GünterZöchbauer Obwohl nur 1 wegen '* ngIf' sichtbar ist? Ich bekomme keine Fehler in der Konsole. –

+0

Ah, Entschuldigung, ich habe das erste '* ngIf' verpasst. –

Antwort

3

Nach den obigen Ausführungen von @bhetzie und @ jaime-torres und meine eigene Hypothese untersuchte ich weiter . Es stellt sich heraus, dass das Problem in der Tat mit dem Doppel router-outlet ist.

Meine Lösung war ein LoginModule Modul zu extrahieren und dann in diesem Modul zur Login-Seite umleiten. In allen anderen Fällen route ich zu einem anderen Modul namens SvsModule, das den angemeldeten Inhalt mit einer Seiten-Nav-Struktur anzeigt.

So ist die SvsModule hat folgenden Routing:

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

Und das ProfileComponent verwendet das folgende 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> 

Ich nehme dies als Antwort, aber dank oben genannte Benutzer, mir zu helfen auf meinem Weg.

2

ich das Problem der Doppel Router-Ausgang ist als die Ausführungen legen nahe oben glauben anzuzeigen. Ich habe so etwas in meinem Projekt gemacht.

Dies war meine Lösung:

ich zum ersten Mal einen Dienst erstellt den Zustand des Login, um zu bestimmen (Ich weiß, dass Ereignis-Emitter keine gute Praxis ist, arbeite ich dies zu einem Verhalten Thema auf der Veränderung):

GlobalEventsManager

import { EventEmitter, Injectable } from '@angular/core'; 


@Injectable() 
export class GlobalEventsManager { 
    public showNavBar: EventEmitter<boolean> = new EventEmitter<boolean>(); 



} 

ich eine authguard für meine Routen verwendet, die, wenn die Login-Token abgelaufen sind nicht überprüft.Ich benutzte die angular2-jwt Bibliothek für dieses

AuthGuard

import { Injectable } from '@angular/core'; 
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; 
import { tokenNotExpired } from 'angular2-jwt'; 
import { GlobalEventsManager } from './GlobalEventsManager'; 


    @Injectable() 
    export class AuthGuard implements CanActivate { 

     constructor(private router: Router, private globaleventsManager: GlobalEventsManager) {} 
     canActivate(next: ActivatedRouteSnapshot, 
        state: RouterStateSnapshot) { 

     if (tokenNotExpired('currentUser')) { 
      this.globaleventsManager.showNavBar.emit(true); 
      return true; 

     } else { 
      localStorage.removeItem('currentUser'); 
      this.router.navigate(['/login']); 
      return false; 
     } 

     } 


    } 

Wenn sich ein Benutzer die Anmeldungskomponente in Verwendung, ich die GlobalEventsManager auf true

Anmeldung gesetzt

constructor(
     private router: Router, 
     private authenticationService: AuthenticationService, 
     private globaleventsManager: GlobalEventsManager) { } 

ngOnInit() { 
     // reset login status 

     this.authenticationService.logout(); 
     this.globaleventsManager.showNavBar.emit(false); 
    } 

    login() { 
     this.loading = true; 
     this.authenticationService.login(this.model.username, this.model.password) 
      .subscribe((result) => { 
       this.globaleventsManager.showNavBar.emit(true); 
       this.router.navigate(['/']); 

In meiner Navbar abonniere ich den GlobalEventsManager und setze ein boolean Eigenschaft zu dem Ergebnis:

Navbar

import { Component } from '@angular/core'; 
import { Router } from '@angular/router'; 
import { NavActiveService } from '../../../services/navactive.service'; 
import { GlobalEventsManager } from '../../../services/GlobalEventsManager'; 

@Component({ 
    moduleId: module.id, 
    selector: 'my-navbar', 
    templateUrl: 'navbar.component.html', 
    styleUrls:['navbar.component.css'], 
}) 
export class NavComponent { 
    showNavBar: boolean = true; 

    constructor(private router: Router,    
       private globalEventsManager: GlobalEventsManager){ 

    this.globalEventsManager.showNavBar.subscribe((mode:boolean)=>{ 
     this.showNavBar = mode; 
    }); 

    } 

} 

In meinem navbar HTML ich jetzt zwei NavBars erstellen kann, ein navbar hat einfach einen Login-nav und wenn mein authguard bemerkt, dass ein toekn abgelaufen ist oder ein Benutzer ist nicht angemeldet. Es zeigt die Navigationsleiste mit nur Login als Option an. Wenn Sie angemeldet sind, die GlobalEventsManager Wertänderungen und meine in navbar protokolliert wird angezeigt:

Navbar HTML

<div *ngIf="showNavBar"> 
//My logged in navbar 
</div> 
<div *ngIf="!showNavBar"> 
//navbar that just displays login as an option 
</div> 
+0

Funktioniert das für Sie, wenn Sie die 'router-outlet's innerhalb der divs setzen (also insgesamt zwei)? Ich habe das versucht, aber ich denke, dass das Problem durch den '* ngIf' verursacht wird, der Digest ist bereits fertig und dann wird der 'Router-Ausgang' zum DOM hinzugefügt. Oder sowas ähnliches denke ich jetzt zumindest –

+0

Du solltest immer nur den einen Router-Ausgang haben. Ich denke, das ist das Problem, das Sie gerade vorgeschlagen haben – Bhetzie

0

Setzen Sie Ihre navigate Anruf in einem ngZone. (Angular 5)

import { NgZone } from "@angular/core"; 
import { Router } from "@angular/router"; 

constructor(
    private ngZone: NgZone, 
    private router: Router 
) {} 

... 

this.ngZone.run(() => { 
    this.router.navigate(['/profile']); 
}); 
Verwandte Themen