2016-11-08 11 views
16

ValuesComponentは、Valueの配列をHTMLテーブルに表示しているとします。優秀なプログラマーとすべてのビーイング Resolveサービスでエラーを処理する

// in value.ts 
export class Value { ... } 
// in values.component.ts 
@Component(...) 
export class ValuesComponent { ... } 

、私は値を提供する責任がある別のクラスを作成しました。 ValuesServiceとしましょう。

// in values.service.ts 
@Injectable() 
export class ValuesService 
{ 
    public getValues(): Observable<Value[]> 
    { 
     ... 
    } 
} 

サービスは、Webサービスから値を取得しているとします。私のコンポーネントに直接サービスを注入するのではなく、今 /api/values

、私は角度ルータがに移動する前に値をプリフェッチようにしたいですコンポーネント

私はResolveサービスクラスを作成し、ルータモジュールに接続しました。

// in values-resolver.service.ts 
export class ValuesResolverService implements Resolve<Value[]> { 
    constructor(private backend: ValuesService) { 
    } 

    public resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Value[]> { 
     return this.backend.getValues(); 
    } 
} 
// In app.module.ts (in @NgModule()) 
imports: [ 
    RouterModule.forRoot([{ 
    path: 'values', 
    component: ValuesComponent, 
    resolve: { values: ValuesResolverService } 
    }]) 
] 

どのように私はこれまでやっていますか?良い?次に、ValuesService.getValues()が失敗したときのエラー処理をどこに置くのですか? (接続エラー、内部サーバーエラー、...)

ユーザーが/#/valuesルートに移動しようとしたときにエラーが発生すると、エラーをコンソールに記録してナビゲーションを停止します。理想的には、ユーザーを/#/errorルートにリダイレクトしたいと思います(サンプルコードには示されていません)。

+0

この質問には、正確に何が起こるべきかについては言及されていません。 – estus

+0

単純な 'console.log'は問題ありません。私はそれを置く場所と戻ってくるもの(もしあれば)を知る必要があります。 –

+0

それから問題は、リゾルバではなく、オブザーバブルについてです。これは 'this.backend.getValues()。catch(...)'を返します。 – estus

答えて

3

このような状況では、サービスはエラーを処理し、必要なルートにリダイレクトする必要があります。 catchメソッドは、解決中に空のケースを処理しながら、空のObservable(解決ガードが解決するため)を返します。この

export class ValuesService { 
    constructor(private http:Http, private router:Router) {} 

    getValue() { 
     this.http.get('/some/url').map((response:Response) => { 
      // Map your response to a model here 
     }).catch((response:Response) => { 
      // Handler case for different status 
      this.router.navigate(['/error']); 
      return Observable.empty(); 
     }) 
    } 
} 

そして次

また
export class ValueResolveGuard implements Resolve<Value[]> { 

    constructor(private valueService:ValueService) {} 

    resolve() { // You don't need the route & state if you're not gonna use them 
     this.valueService.getValue().toPromise().then((values:Values[]) => { 
      if (!values) { // For the Observable.empty() case 
       // return some default stuff 
      } 
      return values; 
     }) 
    } 
} 

ようになり、ガードのような

何かが、あなたは、具体的に観察を返すようにしたい場合(この場合の違いを作るべきではありません、解決ガードは観察可能なものと約束を受け入れるので)、このようなことをすることができます。最初の()が必要です

this.valueService.getValue().first().catch({} => { 
     // return some default value. 
}); 

お知らせ、返された観測可能で、観察可能な終端になるようにそう決意ガードが解決されないでしょう。空のobservableのfirst()呼び出しがエラーを投げるため、キャッチが必要です。

+4

私はサービスが一般的にナビゲーションを処理することには同意しませんが、特に失敗したゲッターの副作用としてのナビゲーションがあります。私はゲッターが副作用のないことを好む。 –

+0

私はそれがサービスがどのように使われているかに至るまで沸騰していると思います。サービスは、共通の機能のポイントでなければなりません。それが間違っていると予想されるならば、ルートは常に更新されるべきです、そして、私はそれが正しい場所だと思います。 サービスが複数の異なる実行ポイントから呼び出され、同じ動作が必要な場合、同じルーティングをサービス内に配置しないと、コードがDRYにならないことになります。 このサービスの目的は何ですか?これは、さらに必要とされる機能を特定するのに役立ちます。 –

+0

'catch'関数を抽出して別のファイルに入れることができます。それで、どこでも再利用するのは簡単です: '.getValues()。catch(navigateToErrorPage)'。それは私の味のために十分乾燥しています。 –