我有一个下拉文本框,可以进行预先键入搜索。当我搜索一个有效的项目名称(存在于数据库中(时,搜索工作正常,并在下拉列表中返回一个项目列表,以便在键入时从中进行选择。但是当我搜索无效文本时,API返回一个400错误(这很好(,然后HttpErrorInterceptor
在catchError()
方法中拦截该响应,并弹出一个错误弹出窗口。我不希望弹出错误,我希望它将错误转发到文本框逻辑,这样我就可以在下拉列表中显示"未找到项目"。
文本框html(使用Angular的NgbTypeahead(:
<input
id="searchText"
type="text"
[(ngModel)]="selectedItem"
(selectItem)="onSelectItem($event)"
formControlName="searchText"
[ngbTypeahead]="search"
#instance="ngbTypeahead" />
文本框逻辑:
search = (input: Observable<string>) => {
return input.pipe(
debounceTime(500),
distinctUntilChanged(),
switchMap((text) => text.length < 2 ? this.clearItems() //clearItems() is irrelavant
: this.itemService.getItemSearchData(text).pipe(
map(responseObj => {
const itemList = responseObj.data ? orderBy(responseObj.data, ['itemName'], ['asc']) : [];
if (itemList.length === 0) {
// this is what I want it to do when I get the error response
itemList.push({ itemName: 'No Items Found' } as ItemList);
}
return itemList;
})
)));
}
// This is in the ItemService class.
getItemSearchData(searchTerm: string): Observable<any> {
const searchItem = {
"filterBy": {
"key": "itemname",
"value": searchTerm
}
}
return this.http.post(this.itemApiUrl, searchItem, { headers: this.headers });
}
这就是拦截器:
@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
constructor(private matDialog: MatDialog) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request)
.pipe(
catchError((error: HttpErrorResponse) => {
let errorMessage = 'Unknown error!';
if (error.error instanceof ErrorEvent) {
errorMessage = `Error: ${error.error.message}`;
} else {
errorMessage = `Error Code: ${error.status}nMessage: ${error.message}`;
}
// the error popup. I DON'T want to throw this when I get the 404 response.
this.matDialog.open(PopupComponent, {
data: { actionDesctiption: errorMessage, isError: true },
panelClass: 'custom-dialog-container'
});
return throwError(error);
})
);
}
我试过这样做:Angular:拦截HTTP错误并继续链,但顶级解决方案的return of(new HttpResponse...;
语句给了我错误Type 'Observable<unknown>' is not assignable to type 'Observable<HttpEvent<any>>'
。我还尝试返回next.handle(request)
和new Observable<HttpEvent<any>>()
。
当我在map(responseObj =>
行放置断点时,它总是说";responseObj未定义";。
当API返回400错误时,如何使下拉列表显示"未找到项目"?
从API返回的数据的结构尚不清楚。假设API以以下格式返回数据:{ itemName: string }[]
(即{ itemName: string }
对象的数组(,则可以使用http拦截器检查404错误,然后更改响应,如下所示:
import { HttpRequest, HttpResponse, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { HttpErrorResponse } from '@angular/common/http';
import { of, throwError } from 'rxjs';
@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
constructor(private matDialog: MatDialog) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request)
.pipe(
catchError((error) => {
let errorMessage = 'Unknown error!';
if (error.error instanceof ErrorEvent) {
errorMessage = `Error: ${error.error.message}`;
} else {
errorMessage = `Error Code: ${error.status}nMessage: ${error.message}`;
}
// check for a 404 error response
if (error instanceof HttpErrorResponse && error.status === 404) {
return this.returnCustomData([{ itemName: 'No Items Found' }]); // returns a response, and doesn't throw the error
}
// the error popup. I DON'T want to throw this when I get the 404 response.
this.matDialog.open(PopupComponent, {
data: { actionDesctiption: errorMessage, isError: true },
panelClass: 'custom-dialog-container'
});
return throwError(error);
})
);
}
private returnCustomData(body) {
return of(new HttpResponse({ status: 200, body }));
}
}
注意:再次假设API返回一个{ itemName: string }
对象数组,这就是为什么我在调用returnCustomData
时在数组中使用一个对象。请记住更改发送到returnCustomData
的数据对象,使其与API返回的实际数据格式相匹配,就好像它只返回了一个结果,其中包含"未找到项目"。
我知道您的拦截器可以处理任何请求的所有HTTP错误,但是,由于您在组件中需要该消息错误,不如在服务管道中添加catchError?
search = (input: Observable<string>) => {
return input.pipe(
debounceTime(500),
distinctUntilChanged(),
switchMap((text) => text.length < 2 ? this.clearItems()
: this.itemService.getItemSearchData(text)
.pipe(
map(responseObj => {
const itemList = responseObj.data ? orderBy(responseObj.data, ['itemName'], ['asc']) : [];
return itemList;
}),
catchError(() => {
itemList.push({ itemName: 'No Items Found' } as ItemList));
of('');
}
)));
}