如何解决根据 RxJS HTTP 请求中的用户输入检查对象数组中的对象是否存在 服务完整的服务列表组件模板
通过 RxJS 使用数据/操作流,如果用户输入无效的托架编号,我想返回/传递错误。如果我的代码与用户输入的数字相匹配,我的代码目前将返回一个 bay 对象,但是如果用户输入了一个在我的列表中不存在的无效的 bay 编号,我不知道如何抛出错误海湾
- 为了让我在多个组件/页面之间共享数据,我在 BayService 类中完成了大部分工作:
private baysUrl = 'api/bays';
bays$ = this.http.get<Bay[]>(this.baysUrl)
.pipe(
tap(data => console.log('Bays: ',JSON.stringify(data))),catchError(this.handleError)
);
/*--------------------------------------------------------------*/
// Grab A Single Bay
private baySelectedSubject = new BehaviorSubject<number>(0);
baySelectedAction$ = this.baySelectedSubject.asObservable();
selectedBay$ = combineLatest([
this.bays$,this.baySelectedAction$
])
.pipe(
map(([bays,selectedBayNumber]) =>
bays.find(bay => bay.bayCode === selectedBayNumber)
),);
selectedBayChanged(selectedBayNumber: number): void {
this.baySelectedSubject.next(selectedBayNumber);
}
- 我通过创建 BehaviorSubject 创建了一个 Action 流。然后我创建了一个方法来将一个值发送到我的 Action 流上。然后,我在
bay.page.ts
中调用此方法,在其中传递输入参数,然后将其发送到我的数据流。 - 然后我将我的数据流和我的动作流结合起来,然后返回一个与我的动作流中的值相匹配的单个海湾对象。
- 问题:所以,我已经可以将用户输入的值发送到我的 observable 中,并根据数字返回 bay 对象,如下所示:
onSubmit() {
this.bayDoesNotExistError = false;
this.bayService.selectedBayChanged(this.bayForm.get('bayStart').value);
this.navCtrl.navigateForward([`/results/`]);
this.bayForm.reset();
}
,但是如何处理无效号码?例如,当用户在输入数字后按下提交按钮时,如何根据我的 observable 检查它是否无效,然后将某些内容返回给我的组件以显示在 UI 上?目前,我在客户端检查用户键入的内容,然后显示错误,但我需要实际检查输入值是否确实存在于我的 Observable
对不起,如果我没有很好地解释这一点,因为我正在努力弄清楚如何措辞。
这是我的 BayService: BayService.ts
这是我的 Bay.page.ts:Bay.page.ts
解决方法
我认为最简单的解决方案是为您的响应创建一个包装器。
export interface BaySelectionResponse {
type: BayResponseType;
message: string;
bay: Bay;
}
export enum BayResponseType {
ERR = "Bay Error",OK = "Success",NOT_IN_LIST = "BAY NOT FOUND IN LIST"
}
通过这种方式,您可以正确地分离职责。
您的服务将根据响应分配状态和消息,您的页面可以决定如何实现显示结果。
使用这种方法,您甚至可以根据您的服务返回的状态,将结果显示分成具有适当模板的自己的组件。
示例
服务
首先,让我们创建一个服务,它的作用是检查我们的遥控器的可用数据:
@Injectable({providedIn: 'root'})
export class ApiLookupService {
}
首先,我们需要一个方法来简单地查询我们的遥控器所有可能的值。我已经使用 rxjs of
函数 see here
mockNumbersEndpoint() {
return of([1,3,7,9,13])
}
其次,我们需要一个方法,该方法将接受来自消费者(即我们的路由组件,将利用我们的服务)的输入,该方法可以根据给定的输入值检查响应。
checkValidity(input: number): Observable<ValidityResponseModel> {
// pipe the response from the api,and switch it into a ValidityResponseModel
return this.mockNumbersEndpoint().pipe(
switchMap(apiResponse => {
const validity = {} as ValidityResponseModel;
// check if the user's input is valid: Exists in response from server
if (apiResponse.some(number => input == number)) {
return of(this.createValidityResponse(
`Your chosen value ${input} is available`,ValidityResponseTypes.SUCCESS,input
));
}
// if our code reaches this point,it means we did not find the users input
return of(this.createValidityResponse(
`Your chosen value ${input} is NOT available`,ValidityResponseTypes.INVALID,input
));
}),// we have now left the level of the 'switch' and are back in the pipe.
// We include catchError to handle if any error is thrown,such as network issues.
catchError(error => {
return of(this.createValidityResponse(
"Something went wrong with your request",ValidityResponseTypes.ERR,input
));
})
)
}
最后,我添加了一个实用函数,它将响应重组为 ValidityResponseType
createValidityResponse(message: string,responseType: ValidityResponseTypes,response: number): ValidityResponseModel {
return {
message,responseType,response
} as ValidityResponseModel
}
完整的服务列表
@Injectable({providedIn: 'root'})
export class ApiLookupService {
mockNumbersEndpoint() {
return of([1,13])
}
checkValidity(input: number): Observable<ValidityResponseModel> {
return this.mockNumbersEndpoint().pipe(
switchMap(apiResponse => {
const validity = {} as ValidityResponseModel;
if (apiResponse.some(number => input == number)) {
return of(this.createValidityResponse(
`Your chosen value ${input} is available`,input
));
}
return of(this.createValidityResponse(
`Your chosen value ${input} is NOT available`,catchError(error => {
return of(this.createValidityResponse(
"Something went wrong with your request",input
));
})
)
}
createValidityResponse(message: string,response
} as ValidityResponseModel
}
}
使用服务的组件
由于在最初的问题中,您在用户按 Enter 键时执行检查,因此我选择实现一个表单。
组件
@Component({
templateUrl: './demo.component.html',styleUrls: ['./demo.component.scss']
})
export class DemoComponent implements OnInit {
group: FormGroup;
responseType = ValidityResponseTypes;
validityResponse!: ValidityResponseModel;
constructor(private fb: FormBuilder,private service: ApiLookupService) {
this.group = fb.group({
input: fb.control(0,[Validators.minLength(1)])
})
}
ngOnInit(): void {
}
// ngSubmit.
formSubmittal() {
let v = this.group.get('input')?.value;
if (this.group.dirty && this.group.valid) {
this.group.reset();
this.checkValidity(v);
}
}
// pipe and take(1) to avoid having to manually unsubscribe.
checkValidity(num: number) {
this.service.checkValidity(num).pipe(take(1)).subscribe(responseFromApi => {
// logic based on response here
this.validityResponse = responseFromApi;
})
}
}
模板
<h2>demonstration</h2>
<div class="method">
<!-- ngSubmit will capture the Enter key event. -->
<form [formGroup]="group" (ngSubmit)="formSubmittal()">
<input type="number" formControlName="input">
</form>
</div>
<div class="result" [ngClass]="{'success': validityResponse?.responseType == responseType.SUCCESS,'invalid': validityResponse?.responseType == responseType.INVALID}">
{{validityResponse?.message}}
</div>
一旦我们得到服务的响应,我们就会根据响应类型设置样式,并在服务中显示为我们准备的消息。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。