Angular2:可观察订阅失败时如何重定向到登录页面?
Angular2 : How to redirect to the login page when observable subscription fails?
在文件auth-guard-service.ts中,为什么调用this.router.navigateByUrl('/ login') 不工作,同时打印警告消息?另一个文件中的另一个调用 (auth.service.ts) 工作正常。
auth-guard-service.ts
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { Domain } from 'domain';
import { AuthService } from './auth.service';
@Injectable()
export class AuthGuardService implements CanActivate {
private domain: Domain = new Domain();
constructor(private router: Router) {}
public canActivate(): Observable<boolean>|Promise<boolean>|boolean {
return Observable.create(
(observer) => {
this.domain.isauth()
.subscribe(
(res) => {
observer.next(true);
},
(err) => {
alert('You need to be authentificated to access this content');
// The call to navigateByUrl below does not work. To fix.
this.router.navigateByUrl('/login');
}
);
}
);
}
auth.service.ts
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Observable } from 'rxjs';
import { Domain } from 'domain';
import { ConfigService } from './config.service';
@Injectable()
export class AuthService {
private authObject: Observable<boolean>;
private domain: Domain = new Domain();
constructor(private router: Router) {}
public login(login: string, password: string) : void {
this.authObject = this.domain.auth(login, password);
alert('Connecting... Please wait.');
this.authObject.subscribe(
(value) => {
this.router.navigateByUrl('../view/dashboard');
}
);
}
public logout() : void {
alert('Going to logout...');
this.domain.logout();
this.router.navigateByUrl('/login');
}
}
app.routing.ts
import { ModuleWithProviders } from '@angular/core';
import {
Routes,
RouterModule
} from '@angular/router';
import { LoginComponent } from './login';
import {
DashboardComponent,
ViewComponent
} from './view';
import { AuthGuardService } from './services';
const appRoutes: Routes = [
{
path: 'view',
component: ViewComponent,
canActivate: [AuthGuardService],
children: [
{
path: 'dashboard',
component: DashboardComponent
}
{
path: '',
redirectTo: 'dashboard',
pathMatch: 'full'
}
]
},
{
path: 'login',
component: LoginComponent
}
{
path: '**',
redirectTo: 'view'
}
];
export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes, { useHash: true });
如果出现错误(如果用户未连接),我只想重定向到登录页面。
配置:Angular2
From angular documentation, "Always specify the complete
absolute path when calling router's navigateByUrl method."
改用router.navigate
:
public canActivate(): Observable<boolean>|Promise<boolean>|boolean {
return Observable.create(
(observer) => {
this.domain.isauth()
.subscribe(
(res) => {
observer.next(true);
},
(err) => {
alert('You need to be authentificated to access this content');
// The call to navigateByUrl below does not work. To fix.
this.router.navigate(['/login']);
}
);
}
);
}
简短的解决方案(没有 alert())是替换
this.router.navigate(['/login']);
来自
observer.next(this.router.navigate(['/login']));
或者,如果我想保留警报消息:
observer.next(false);
alert('You need to be authentificated to access this content');
this.router.navigateByUrl('/login');
- 简短说明:
我们需要调用observer.next()来解锁回调栈并执行下一条回调指令;
- 更详细的解释:
1) 如果你看代码,我订阅了一个观察者。在我出错的情况下,没有执行下一个回调的指令,所以堆栈可能是 'blocked'.
2) 根据 documentation,navigateByUrl() 是一个 Promise,它通过回调工作。所以navigateByUrl()可能需要前一个观察者先'unblocked',然后才依次执行。
3) 我们可能想知道为什么当两条指令在同一个块上时 alert() 没有任何问题打印出错误消息。原因可能是因为 Node 在不同的队列中执行打印堆栈(alert()、console.log() 等...)。
PS : 我不是Angular2/NodeJS/Callback/Promise/Observable的高手所以我不确定答案。如果您知道什么,请随时回答。 :)
这是我的回答。 subscribe 方法有 3 个参数,next、error 和 completed。订阅方法完成后重定向。在这种情况下,它将转到仪表板组件。
login() {
this.authService.logIn(this.model).subscribe(
next => {
this.alertify.success('Logged in successfully');
},
error => {
this.alertify.error(error);
},
() => {
this.router.navigate(['/dashboard']);
}
);
}
在文件auth-guard-service.ts中,为什么调用this.router.navigateByUrl('/ login') 不工作,同时打印警告消息?另一个文件中的另一个调用 (auth.service.ts) 工作正常。
auth-guard-service.ts
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { Domain } from 'domain';
import { AuthService } from './auth.service';
@Injectable()
export class AuthGuardService implements CanActivate {
private domain: Domain = new Domain();
constructor(private router: Router) {}
public canActivate(): Observable<boolean>|Promise<boolean>|boolean {
return Observable.create(
(observer) => {
this.domain.isauth()
.subscribe(
(res) => {
observer.next(true);
},
(err) => {
alert('You need to be authentificated to access this content');
// The call to navigateByUrl below does not work. To fix.
this.router.navigateByUrl('/login');
}
);
}
);
}
auth.service.ts
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Observable } from 'rxjs';
import { Domain } from 'domain';
import { ConfigService } from './config.service';
@Injectable()
export class AuthService {
private authObject: Observable<boolean>;
private domain: Domain = new Domain();
constructor(private router: Router) {}
public login(login: string, password: string) : void {
this.authObject = this.domain.auth(login, password);
alert('Connecting... Please wait.');
this.authObject.subscribe(
(value) => {
this.router.navigateByUrl('../view/dashboard');
}
);
}
public logout() : void {
alert('Going to logout...');
this.domain.logout();
this.router.navigateByUrl('/login');
}
}
app.routing.ts
import { ModuleWithProviders } from '@angular/core';
import {
Routes,
RouterModule
} from '@angular/router';
import { LoginComponent } from './login';
import {
DashboardComponent,
ViewComponent
} from './view';
import { AuthGuardService } from './services';
const appRoutes: Routes = [
{
path: 'view',
component: ViewComponent,
canActivate: [AuthGuardService],
children: [
{
path: 'dashboard',
component: DashboardComponent
}
{
path: '',
redirectTo: 'dashboard',
pathMatch: 'full'
}
]
},
{
path: 'login',
component: LoginComponent
}
{
path: '**',
redirectTo: 'view'
}
];
export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes, { useHash: true });
如果出现错误(如果用户未连接),我只想重定向到登录页面。
配置:Angular2
From angular documentation, "Always specify the complete absolute path when calling router's navigateByUrl method."
改用router.navigate
:
public canActivate(): Observable<boolean>|Promise<boolean>|boolean {
return Observable.create(
(observer) => {
this.domain.isauth()
.subscribe(
(res) => {
observer.next(true);
},
(err) => {
alert('You need to be authentificated to access this content');
// The call to navigateByUrl below does not work. To fix.
this.router.navigate(['/login']);
}
);
}
);
}
简短的解决方案(没有 alert())是替换
this.router.navigate(['/login']);
来自
observer.next(this.router.navigate(['/login']));
或者,如果我想保留警报消息:
observer.next(false);
alert('You need to be authentificated to access this content');
this.router.navigateByUrl('/login');
- 简短说明:
我们需要调用observer.next()来解锁回调栈并执行下一条回调指令;
- 更详细的解释:
1) 如果你看代码,我订阅了一个观察者。在我出错的情况下,没有执行下一个回调的指令,所以堆栈可能是 'blocked'.
2) 根据 documentation,navigateByUrl() 是一个 Promise,它通过回调工作。所以navigateByUrl()可能需要前一个观察者先'unblocked',然后才依次执行。
3) 我们可能想知道为什么当两条指令在同一个块上时 alert() 没有任何问题打印出错误消息。原因可能是因为 Node 在不同的队列中执行打印堆栈(alert()、console.log() 等...)。
PS : 我不是Angular2/NodeJS/Callback/Promise/Observable的高手所以我不确定答案。如果您知道什么,请随时回答。 :)
这是我的回答。 subscribe 方法有 3 个参数,next、error 和 completed。订阅方法完成后重定向。在这种情况下,它将转到仪表板组件。
login() {
this.authService.logIn(this.model).subscribe(
next => {
this.alertify.success('Logged in successfully');
},
error => {
this.alertify.error(error);
},
() => {
this.router.navigate(['/dashboard']);
}
);
}