[英]Subscribe to observable, async map result with input from dialog, use result from map to route
I am calling an API-service which returns an Observable - containing an array of elements.我正在调用一个 API 服务,它返回一个 Observable - 包含一个元素数组。
apiMethod(input: Input): Observable<ResultElement[]>
From this I have been choosing the first element of the array, subscribing to that.从这里我一直在选择数组的第一个元素,订阅那个。 Then used that element to route to another page like this:
然后使用该元素路由到另一个页面,如下所示:
this.apiService
.apiMethod(input)
.pipe(map((results) => results[0])
.subscribe(
(result) => {
return this.router.navigate('elements/', result.id)
}
)
This works just fine.这工作得很好。
Problem is, I do not want to just use the first element, I want a MatDialog, or other similar to pop up, and give the user option of which element to choose, and THEN route to the correct one.问题是,我不想只使用第一个元素,我想要一个 MatDialog 或其他类似的元素弹出,并为用户提供选择哪个元素的选项,然后路由到正确的元素。
If the list only contain one element though, the dialog should not show, and the user should be routed immediately.如果列表只包含一个元素,则不应显示对话框,并且应立即路由用户。
I have tried to open a dialog in the .pipe(map())
function, but the subscribe()
happens before I get answer from the user, causing it to fail.我试图在
.pipe(map())
函数中打开一个对话框,但是subscribe()
发生在我从用户那里得到答案之前,导致它失败。 And I am not sure if that even is the correct approach.我不确定这是否是正确的方法。 How would any of you solve this problem?
你们中的任何人将如何解决这个问题?
I would solve it using the following method:我将使用以下方法解决它:
options: any;
this.apiService
.apiMethod(input)
.subscribe(
(result) => {
if (result.length === 1) {
this.router.navigate([result[0]]);
return;
}
options = result;
}
)
<modal-component *ngIf="options.length > 0"></modal-component>
html
<div (click)="redirect(value)">option 1</div>
ts
redirect(value) {
this.router.navigate([value]);
}
That would be the most straight forward那将是最直接的
Two possible options:两种可能的选择:
The example below is a sketch of using an Observable to keep track of the component's state.下面的示例是使用 Observable 跟踪组件状态的草图。
readonly getResultsSubject = new Subject<MyInput>();
readonly resultSelectedSubject = new Subject<ResultType>();
private readonly apiResults$ = this.getResultsSubjects.pipe(
switchMap((input) => this.apiMethod(input))
);
readonly state = combineLatest([
this.apiResults$.pipe(map(results => (s) => results.length === 1
? { ...s, results, selectedResult: x[0], showModal: false }
: { ...s, results, showModal: results.length > 1 })),
this.resultSelectedSubject.pipe(map(selectedResult => (s) => ({ ...s, selectedResult })))
]).pipe(
scan((s, reducer) => reducer(s), { }),
shareReplay(1)
);
ngOnInit() {
this.state.pipe(
filter(x => !!x.selectedResult)
).subscribe(x => this.router.navigate('elements/', x.selectedResult.id));
}
I've been using this pattern a lot lately.我最近一直在使用这种模式。 It makes it pretty easy the number of actions and properties of the state grow.
它使得状态的动作和属性的数量增长变得非常容易。
I would create a DialogComponent
that takes in the list of choices as an input, and emits the chosen item when it's closed.我将创建一个
DialogComponent
,它将选择列表作为输入,并在关闭时发出所选项目。
Then, create a helper method ( maybe call it promptUser
) that simply returns an observable that emits the selected value:然后,创建一个辅助方法(可能称为
promptUser
), promptUser
返回一个发出所选值的可观察对象:
this.apiService.apiMethod(input)
.pipe(
switchMap(results => results.length > 1
? this.promptUser(results)
: of(results[0])
)
)
.subscribe(
result => this.router.navigate('elements/', result.id)
);
Here we simply use switchMap
to return an observable that emits the proper item.这里我们简单地使用
switchMap
来返回一个发出正确项目的 observable。 If the length is greater than 1, we return the helper method that displays the dialog and emits the chosen item, else just emit the first ( only ) item.如果长度大于 1,我们返回显示对话框并发出所选项目的辅助方法,否则只发出第一个(唯一)项目。 Notice that we wrapped plain value with
of
since within switchMap, we need to return observable.请注意,我们在 switchMap 中使用
of
包装了普通值,我们需要返回 observable。
In either case, the desired item is emitted and received by your subscribe callback.在任何一种情况下,您的订阅回调都会发出和接收所需的项目。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.