J'utilise un Guard sur une application Angular pour résoudre les données critiques initiales. Sur la version 4 de Angular, je le traitais comme ceci:
// 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();
}
}
Puisque la nouvelle version de Http sur Angular 5 n’utilise plus la propriété .map()
, cela ne fonctionne pas.
Si je change .map()
en .subscribe()
, aucune erreur ne sera renvoyée, mais l'application ne sera jamais résolue correctement. D'autre part, l'utilisation de .first()
et/ou .map()
génère des erreurs, comme prévu dans cette version.
Que dois-je faire dans ce cas?
Je n'ai besoin d'activer cette route que si et quand les données initiales sont chargées.
Modifier pour ajouter des informations sur la fonction apiGet
:
constructor(private _http: HttpClient) {}
public apiGet(url: string): any {
return this._http
.get(this.apiUrl + url)
.catch(this.handleError.bind(this));
}
Donc, tout d’abord, évitez d’utiliser any
lorsque cela est possible, surtout lorsque vous savez quel type appartient à quel endroit.
export interface FooInterface {
status: string;
fooString : string;
fooNumber : number;
}
Dans un premier temps, je vais définir l’interface du service de manière propre, puis je vais reformuler la classe de garde.
RÉPONSE MISE À JOUR for 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);
})
);
}
}
La classe de garde:
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))
);
}
RÉPONSE ORIGINALE pour 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);
});
}
La classe de garde:
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)
});
}
il suffit d'importer l'opérateur map
et cela fonctionnera:
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;
});
}