質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Angular

Angularは、JavaScriptフレームワークです。AngularJSの後継であり、TypeScriptベースで実装されています。機能ごとに実装を分けやすく、コードの見通しが良いコンポーネント指向です。

Q&A

解決済

1回答

2219閲覧

【Angular】データ取得を待ってからビューを描写したいが、エラー受信時は処理が中断してしまう

waito

総合スコア23

Angular

Angularは、JavaScriptフレームワークです。AngularJSの後継であり、TypeScriptベースで実装されています。機能ごとに実装を分けやすく、コードの見通しが良いコンポーネント指向です。

0グッド

0クリップ

投稿2020/10/20 09:08

編集2020/10/20 18:10

やりたいこと

Angular10のHttpClinetでAPIからデータを取得し、
その取得結果を待ってからビューの描写を開始したいです。

そこで、以下を参考にして、
HttpClinetを利用してAPIからデータを取得するサービス(ScoresClientService)と、
Resolveインターフェースを実装したサービス(DetailResolverService)を作成して、
コンポーネントのルーティング前にデータ取得処理を実行するようにしました。

問題

正常時は、意図した通り、データ取得を待ってからビューを描写出来ました。
しかし、HTTPエラー受信時は、処理出来ずに何も描写出来なくなってしまいました。
コンポーネント側で何も処理出来ていない状態です。

発生しているエラー

Google ChromeのDevToolのConsoleに以下のエラーが出ています。
一つ目は500エラーを受信したというメッセージなのであまり関係ないと思います。
二つ目のエラーが本事象の直接原因だと思います。
調べても分からなかったのですが、
HttpClinetはエラーの場合、HttpErrorResponseを受信するので、
それを扱えていないのではないかと推測しています。

Failed to load resource: the server responded with a status of 500 (Internal Server Error)
core.js:4197 ERROR Error: Uncaught (in promise): HttpErrorResponse: {"headers":{"normalizedNames":{},"lazyUpdate":null},"status":500,"statusText":"Internal Server Error","url":"http://localhost:4200/api/scores","ok":false,"name":"HttpErrorResponse","message":"Http failure response for http://localhost:4200/api/scores: 500 Internal Server Error","error":null} at resolvePromise (zone.js:832) at resolvePromise (zone.js:784) at zone.js:894 at ZoneDelegate.invokeTask (zone.js:421) at Object.onInvokeTask (core.js:27425) at ZoneDelegate.invokeTask (zone.js:420) at Zone.runTask (zone.js:188) at drainMicroTaskQueue (zone.js:601) at ZoneTask.invokeTask [as invoke] (zone.js:507) at invokeTask (zone.js:1671)

コード

HttpClinetを利用してAPIからデータを取得するサービス(ScoresClientService)

TypeScript

1@Injectable({ 2 providedIn: 'root' 3}) 4export class ScoresClientService { 5 6 constructor(private httpClient: HttpClient) { } 7 8 post(claimNumber: string): Observable<Scores> { 9 // HTTPリクエストの各情報セット 10 const scoresUri = environment.scores_url; 11 const params = { claimNumber: claimNumber }; 12 const headers = { 'Content-Type': 'application/json' }; 13 14 // スコア詳細を取得し、取得結果を呼び出し元に返す 15 return this.httpClient.post<Scores>(scoresUri, params, { headers: headers }); 16 } 17}

Resolveインターフェースを実装したサービス(DetailResolverService)

TypeScript

1@Injectable({ 2 providedIn: 'root' 3}) 4export class DetailResolverService implements Resolve<Scores> { 5 6 constructor(private client: ScoresClientService) { } 7 8 resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Scores> { 9 const claimNumber = route.paramMap.get('claimNumber'); 10 return this.client.post(claimNumber); 11 } 12}

ルーティング設定(app-routing.module.tsの一部抜粋)

TypeScript

1const routes: Routes = [ 2 { 3 path: 'detail/:claimNumber', 4 component: DetailComponent, 5 resolve: { 6 detail: DetailResolverService 7 } 8 } 9];

コンポーネント(DetailComponentの一部抜粋)

TypeScript

1constructor(private route: ActivatedRoute) 2 ) { } 3 4this.route.data.subscribe( 5 response => {(省略) 6 }, error => {(省略)

確認したこと

  • DetailResolverServiceを使わないで、コンポーネントから直接ScoresClientServiceを呼び出せば、

HTTPエラー受信時も正常に処理できる。
(その代わり、データ取得を待ってから描写を開始できなくなる)

  • DetailResolverServiceはScoresClientServiceからObservableを受け取っている。

以下のようにDetailResolverServiceを書き換えると、console.log(response)でObservableのオブジェクトを出力できる。
(try catchに意味はないです。あわよくばcatchしてエラーページに飛ばせないか考えましたが、出来ませんでした)

  • HTTPエラー500以外のエラー(400)でも本事象が発生すること。

TypeScript

1@Injectable({ 2 providedIn: 'root' 3}) 4export class DetailResolverService implements Resolve<any> { 5 6 constructor(private client: ScoresClientService, private router: Router) { } 7 8 resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> { 9 const claimNumber = route.paramMap.get('claimNumber'); 10 try { 11 const response = this.client.post(claimNumber); 12 console.log('受信確認'); 13 console.log(response) 14 return response; 15 } catch(e) { 16 this.router.navigate(['/list/error']); 17 } 18 } 19}

以上です。

何か気づくことがあればご教授下さい。
理想はObservableをDetailComponentに渡せれば良いのですが、
出来なければ、DetailResolverServiceでエラーハンドリングして、
HTTPエラー受信時にはエラーページに飛ばすでも良いと思っていますが、
その方法も分からなかったので、もし分かる方がいらっしゃればご教授頂きたいです。

宜しくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

Resolveインターフェースを実装したサービスからエラー(のObservable)を返すことは出来ない?ようで、
DetailResolverServiceでエラーハンドリングでエラーハンドリングする方法で解決しました。

参考までにコードを貼っておきます。
なお、DetailResolverServiceではコメントアウトしていますが、エラーページにリダイレクトもできます。(こちらの方が一般的だと思います。)

TypeScript

1@Injectable({ 2 providedIn: 'root' 3}) 4export class DetailResolverService implements Resolve<Scores> { 5 6 constructor(private client: ScoresClientService, private router: Router) { } 7 8 resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Scores> { 9 const claimNumber = route.paramMap.get('claimNumber'); 10 return this.client.post(claimNumber) 11 .pipe( 12 catchError(error => { 13 // this.router.navigate(['/list/error']); 14 // return EMPTY; 15 return of(null); 16 })); 17 } 18}

TypeScript

1constructor(private route: ActivatedRoute) 2 ) { } 3 4this.route.data.subscribe( 5 response => { 6 if (!response.detail) { 7 (エラー時の処理) 8 return; 9 } 10 (正常時の処理) 11 }, error => {(省略)

投稿2020/10/21 19:54

waito

総合スコア23

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問