在 Angular 5 上等待 Guard 内部的 http
Wait for http inside Guard on Angular 5
我在 Angular 应用程序上使用 Guard 来解析初始关键数据。在 Angular 的第 4 版中,我是这样计算的:
// app.routing.ts
routing = [{
path: '', component: AppComponent, canActivate: [ResolveGuard],
}];
// resolve.guard.ts
@Injectable()
export class ResolveGuard implements CanActivate {
constructor(
private _api: ApiService,
) { }
canActivate(): any {
return this._api.apiGet('my/url').map(response) => {
if ( response.status === 'success') {
// Consume data here
return true;
}
return false;
}).first();
}
}
由于 Http on Angular 5 的新版本不再使用 .map()
属性,因此无法正常工作。
如果我将 .map()
更改为 .subscribe()
,它不会抛出任何错误,但应用程序永远无法正确解析。另一方面,使用 .first()
and/or .map()
会抛出一些错误,如本版本所预期的那样。
遇到这种情况怎么办?
只有在加载初始数据时我才需要激活该路由。
编辑以添加有关 apiGet
函数的信息:
constructor(private _http: HttpClient) {}
public apiGet(url: string): any {
return this._http
.get(this.apiUrl + url)
.catch(this.handleError.bind(this));
}
只需导入 map
操作符即可:
import { Observable } "rxjs/Observable";
import "rxjs/add/operator/map";
canActivate(): Observable<boolean>{
return this._api.apiGet('my/url').map(response => {
if ( response.status === 'success') {
// Consume data here
return true;
}
return false;
});
}
所以,第一件事:尽可能避免使用 any
,特别是当您知道哪种类型属于哪里时。
export interface FooInterface {
status: string;
fooString : string;
fooNumber : number;
}
首先我会以干净的方式定义服务的接口,然后我会重构守卫class。
rxjs
6.x
的更新答案
import { throwError, Observable } from 'rxjs';
import { catchError } from 'rxjs/operators';
@Injectable()
export class FooService {
constructor(private _http: HttpClient) {}
public apiGet(url: string): Observable<FooInterface> {
return this._http
.get<FooInterface>(this.apiUrl + url)
.pipe(
catchError(error => {
// do general error handling if necessary and throw
throwError(error);
})
);
}
}
门卫class:
import { of, Observable } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
@Injectable()
export class ResolveGuard implements CanActivate {
constructor(
private fooService: FooService ,
) { }
canActivate(): Observable<boolean> {
return this.fooService.apiGet('my/url')
.pipe(
map(response => response.status === 'success'),
catchError(error => of(false))
);
}
原始答案 rxjs
5.x
import { _throw } from 'rxjs/observable/throw':
constructor(private _http: HttpClient) {}
public apiGet(url: string): Observable<FooInterface> {
return this._http
.get<FooInterface>(this.apiUrl + url)
.catch(error => {
// do general error handling if necessary and throw
_throw(error);
});
}
门卫class:
import { of } from 'rxjs/observable/of';
@Injectable()
export class ResolveGuard implements CanActivate {
constructor(
private _api: ApiService,
) { }
canActivate(): Observable<boolean> {
return this._api.apiGet('my/url')
.map(response => {
let val = false;
if ( response.status === 'success') {
// Consume data here
val = true;
}
return val;
}).catch(error => {
// consume the error maybe?
of(false)
});
}
我在 Angular 应用程序上使用 Guard 来解析初始关键数据。在 Angular 的第 4 版中,我是这样计算的:
// app.routing.ts
routing = [{
path: '', component: AppComponent, canActivate: [ResolveGuard],
}];
// resolve.guard.ts
@Injectable()
export class ResolveGuard implements CanActivate {
constructor(
private _api: ApiService,
) { }
canActivate(): any {
return this._api.apiGet('my/url').map(response) => {
if ( response.status === 'success') {
// Consume data here
return true;
}
return false;
}).first();
}
}
由于 Http on Angular 5 的新版本不再使用 .map()
属性,因此无法正常工作。
如果我将 .map()
更改为 .subscribe()
,它不会抛出任何错误,但应用程序永远无法正确解析。另一方面,使用 .first()
and/or .map()
会抛出一些错误,如本版本所预期的那样。
遇到这种情况怎么办?
只有在加载初始数据时我才需要激活该路由。
编辑以添加有关 apiGet
函数的信息:
constructor(private _http: HttpClient) {}
public apiGet(url: string): any {
return this._http
.get(this.apiUrl + url)
.catch(this.handleError.bind(this));
}
只需导入 map
操作符即可:
import { Observable } "rxjs/Observable";
import "rxjs/add/operator/map";
canActivate(): Observable<boolean>{
return this._api.apiGet('my/url').map(response => {
if ( response.status === 'success') {
// Consume data here
return true;
}
return false;
});
}
所以,第一件事:尽可能避免使用 any
,特别是当您知道哪种类型属于哪里时。
export interface FooInterface {
status: string;
fooString : string;
fooNumber : number;
}
首先我会以干净的方式定义服务的接口,然后我会重构守卫class。
rxjs
6.x
import { throwError, Observable } from 'rxjs';
import { catchError } from 'rxjs/operators';
@Injectable()
export class FooService {
constructor(private _http: HttpClient) {}
public apiGet(url: string): Observable<FooInterface> {
return this._http
.get<FooInterface>(this.apiUrl + url)
.pipe(
catchError(error => {
// do general error handling if necessary and throw
throwError(error);
})
);
}
}
门卫class:
import { of, Observable } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
@Injectable()
export class ResolveGuard implements CanActivate {
constructor(
private fooService: FooService ,
) { }
canActivate(): Observable<boolean> {
return this.fooService.apiGet('my/url')
.pipe(
map(response => response.status === 'success'),
catchError(error => of(false))
);
}
原始答案 rxjs
5.x
import { _throw } from 'rxjs/observable/throw':
constructor(private _http: HttpClient) {}
public apiGet(url: string): Observable<FooInterface> {
return this._http
.get<FooInterface>(this.apiUrl + url)
.catch(error => {
// do general error handling if necessary and throw
_throw(error);
});
}
门卫class:
import { of } from 'rxjs/observable/of';
@Injectable()
export class ResolveGuard implements CanActivate {
constructor(
private _api: ApiService,
) { }
canActivate(): Observable<boolean> {
return this._api.apiGet('my/url')
.map(response => {
let val = false;
if ( response.status === 'success') {
// Consume data here
val = true;
}
return val;
}).catch(error => {
// consume the error maybe?
of(false)
});
}