web-dev-qa-db-ja.com

Angular 5でGuard内のhttpを待つ

AngularアプリケーションでGuardを使用して、初期の重要なデータを解決しています。バージョン4のAngularでは、次のように処理していました。

_// 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()および/または.map()を使用すると、このバージョンで予想されるように、いくつかのエラーがスローされます。

この場合はどうすればよいですか?

初期データがロードされた場合にのみ、そのルートをアクティブ化する必要があります。


編集して、apiGet関数に関する情報を追加します。

_constructor(private _http: HttpClient) {}

public apiGet(url: string): any {
    return this._http
        .get(this.apiUrl + url)
        .catch(this.handleError.bind(this));
}
_
6
celsomtrindade

したがって、まず最初に、可能な場合、特にどのタイプがどこに属するかがわかっている場合は、anyの使用を避けてください。

export interface FooInterface {
  status: string;
  fooString : string;
  fooNumber : number;
}

最初にサービスのインターフェースをクリーンな方法で定義し、次にガードクラスをリファクタリングします。

更新された回答 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);
           })
        );
  }
}

ガードクラス:

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

元の回答 for 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);
       });
}

ガードクラス:

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)
        });
}
15
Jota.Toledo

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