在 Angular 上订阅 2 种类型的可观察对象
Subscribing to observable of 2 types on Angular
对不起标题,但我找不到更好的标题。
我在发送 GET 命令时调用 return 是 json object 的 HTTP API,但如果资源不足,它将 return 404没有找到。
我正在使用 Angular 9 并且我正在尝试找到一种方法来从服务输出 json object 或 return 上接收到的 HTTP 错误的枚举值同一个 Observable。
请看下面的一些代码:
device.service.ts
getDevice(objectID: number | string): Observable<Device | ResponseStatus> {
return this.http.get<Device>(`http://localhost:8080/Registration/Device/${objectID}`)
.pipe(
catchError(this.handleError)
);
}
handleError(error: HttpErrorResponse): Observable<ResponseStatus> {
switch (error.status) {
case 404: {
return of(ResponseStatus.objectNotFound);
break;
}
case 409: {
return of(ResponseStatus.objectAlreadyExists);
break;
}
}
}
我希望 return ResponseStatus 到我的组件,这样我就可以用同样的方式处理所有错误。
device-item-resolver-service.ts
export class DeviceItemResolverService implements Resolve<Device> {
constructor(private ds: DeviceService, private router: Router) { }
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Device> | Observable<never> {
let objectID = route.paramMap.get('objectID');
return this.ds.getDevice(objectID).pipe(
take(1),
mergeMap(
(item: Device) => {
if (item) {
return of(item);
}
else {
this.router.navigate(['/devices']);
return EMPTY;
}
}
)
);
}
}
显然一切都很顺利。 运行 我可以接收设备的程序,但我找不到在解析器上处理 ResponseStatus 的方法。
拜托,你能帮帮我吗?
不需要使用 mergeMap
,因为在这种情况下 map
应该足够好。
import { map } from 'rxjs/operators';
....
return this.ds.getDevice(objectID).pipe(
take(1),
map(
(item: Device | ResponseStatus) => {
// this if statement I think is the culprit.
// Basically ResponseStatus.objectNotFound is true and it goes here
// I am not sure if instanceof will work but basically you have to find out
// if you're getting Device or ResponseStatus and act accordingly
if (item instanceof Device) {
return item;
}
else {
this.router.navigate(['/devices']);
return null;
}
}
)
);
我无法按照建议使用 typeof
或 instanceof
,所以我在 typescript 中找到了一篇关于高级类型的很棒的文档,如下所示:
https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards
看看下面我是如何解决这个问题的:
首先我定义了一个用户定义的类型保护:
function isDevice(value: Device | ResponseStatus): value is Device {
return (value as Device).objectID !== undefined;
}
然后我在我的原始代码上调用了这个函数:
return this.ds.getDevice(objectID).pipe(
take(1),
mergeMap(
(item: Device | ResponseStatus) => {
if (!item) {
this.router.navigate(['/devices']);
return EMPTY;
}
else if (isDevice(item)) {
return of(item)
}
else {
switch (item as ResponseStatus) {
case ResponseStatus.objectNotFound: {
this.router.navigate(['/devices']);
return EMPTY;
}
}
}
}
)
)
}
请注意,我需要使用 mergeMap
。 map
没用。
对不起标题,但我找不到更好的标题。
我在发送 GET 命令时调用 return 是 json object 的 HTTP API,但如果资源不足,它将 return 404没有找到。 我正在使用 Angular 9 并且我正在尝试找到一种方法来从服务输出 json object 或 return 上接收到的 HTTP 错误的枚举值同一个 Observable。
请看下面的一些代码:
device.service.ts
getDevice(objectID: number | string): Observable<Device | ResponseStatus> {
return this.http.get<Device>(`http://localhost:8080/Registration/Device/${objectID}`)
.pipe(
catchError(this.handleError)
);
}
handleError(error: HttpErrorResponse): Observable<ResponseStatus> {
switch (error.status) {
case 404: {
return of(ResponseStatus.objectNotFound);
break;
}
case 409: {
return of(ResponseStatus.objectAlreadyExists);
break;
}
}
}
我希望 return ResponseStatus 到我的组件,这样我就可以用同样的方式处理所有错误。
device-item-resolver-service.ts
export class DeviceItemResolverService implements Resolve<Device> {
constructor(private ds: DeviceService, private router: Router) { }
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Device> | Observable<never> {
let objectID = route.paramMap.get('objectID');
return this.ds.getDevice(objectID).pipe(
take(1),
mergeMap(
(item: Device) => {
if (item) {
return of(item);
}
else {
this.router.navigate(['/devices']);
return EMPTY;
}
}
)
);
}
}
显然一切都很顺利。 运行 我可以接收设备的程序,但我找不到在解析器上处理 ResponseStatus 的方法。
拜托,你能帮帮我吗?
不需要使用 mergeMap
,因为在这种情况下 map
应该足够好。
import { map } from 'rxjs/operators';
....
return this.ds.getDevice(objectID).pipe(
take(1),
map(
(item: Device | ResponseStatus) => {
// this if statement I think is the culprit.
// Basically ResponseStatus.objectNotFound is true and it goes here
// I am not sure if instanceof will work but basically you have to find out
// if you're getting Device or ResponseStatus and act accordingly
if (item instanceof Device) {
return item;
}
else {
this.router.navigate(['/devices']);
return null;
}
}
)
);
我无法按照建议使用 typeof
或 instanceof
,所以我在 typescript 中找到了一篇关于高级类型的很棒的文档,如下所示:
https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards
看看下面我是如何解决这个问题的:
首先我定义了一个用户定义的类型保护:
function isDevice(value: Device | ResponseStatus): value is Device {
return (value as Device).objectID !== undefined;
}
然后我在我的原始代码上调用了这个函数:
return this.ds.getDevice(objectID).pipe(
take(1),
mergeMap(
(item: Device | ResponseStatus) => {
if (!item) {
this.router.navigate(['/devices']);
return EMPTY;
}
else if (isDevice(item)) {
return of(item)
}
else {
switch (item as ResponseStatus) {
case ResponseStatus.objectNotFound: {
this.router.navigate(['/devices']);
return EMPTY;
}
}
}
}
)
)
}
请注意,我需要使用 mergeMap
。 map
没用。