使用来自对话框的输入订阅可观察的异步地图结果,使用来自地图的结果来路由
Subscribe to observable, async map result with input from dialog, use result from map to route
我正在调用一个 API 服务,其中 returns 一个 Observable - 包含一个元素数组。
apiMethod(input: Input): Observable<ResultElement[]>
由此我一直在选择数组的第一个元素,并订阅它。然后使用该元素路由到另一个页面,如下所示:
this.apiService
.apiMethod(input)
.pipe(map((results) => results[0])
.subscribe(
(result) => {
return this.router.navigate('elements/', result.id)
}
)
这很好用。
问题是,我不想只使用第一个元素,我想要一个 MatDialog 或其他类似的弹出窗口,让用户选择选择哪个元素,然后路由到正确的那个。
如果列表仅包含一个元素,则不应显示对话框,并且应立即路由用户。
我试图在 .pipe(map())
函数中打开一个对话框,但是 subscribe()
在我得到用户的回答之前发生,导致它失败。而且我不确定这是否是正确的方法。你们会如何解决这个问题?
编辑
最终完成了@BizzyBob 建议的部分工作:
在 API 调用中将地图更改为 switchmap,以这种方式进行:
this.apiService
.apiMethod(input)
.pipe(switchMap((results) => this.mapToSingle(results)
.subscribe(
(result) => {
return this.router.navigate('elements/', result.id)
}
)
mapToSingle(ResultElement[])
是这样的:
private mapToSingle(results: ResultElement[]): Observable<ResultElement> {
if (result.length === 1){
return of(results[0]);
}
const dialogConfig = new MatDialogConfig<ResultElement[]>();
dialogConfig.data = results;
const dialogRef = this.dialog.open(ResultDialogComponent, dialogConfig);
return dialogRef.afterClosed();
}
我会用下面的方法解决:
- 通过订阅获取数据(不使用管道)。并将此数据保存在组件变量中
options: any;
this.apiService
.apiMethod(input)
.subscribe(
(result) => {
if (result.length === 1) {
this.router.navigate([result[0]]);
return;
}
options = result;
}
)
- 在模式上使用 ngIf(条件是选项数组的长度 > 0 在接收到数据时显示具有不同选择的组件
<modal-component *ngIf="options.length > 0"></modal-component>
- 当用户(单击)您的模式内的选项时,使用路由器进行重定向。
html
<div (click)="redirect(value)">option 1</div>
ts
redirect(value) {
this.router.navigate([value]);
}
那将是最直接的
两个可能的选择:
- 通过用户输入或使用一个元素获得 api 结果的副作用,为所选结果设置一个“下一个”主题。
- 跟踪组件的总体状态并在状态中设置 selectedResult 时做出适当响应。
下面的示例是使用 Observable 跟踪组件状态的草图。
- 有两个输入流进入状态,来自api的结果和用于选择结果的用户输入。
- 每个流都被转换成一个会修改整体状态的 reducer 函数。
- UI 应该通过异步管道订阅此状态,在适当的时候显示模态,并通过 Subjects 从事件更新更新状态。
- 当 selectedResult 有值时,重定向应该影响状态的改变。
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));
}
我最近经常使用这种模式。这使得状态的动作和属性的数量很容易增长。
我会创建一个 DialogComponent
,它将选项列表作为输入,并在它关闭时发出所选项目。
然后,创建一个辅助方法(可以称之为 promptUser
),它只是 return 一个发出选定值的可观察对象:
this.apiService.apiMethod(input)
.pipe(
switchMap(results => results.length > 1
? this.promptUser(results)
: of(results[0])
)
)
.subscribe(
result => this.router.navigate('elements/', result.id)
);
这里我们简单地使用 switchMap
到 return 一个发出正确项目的 Observable。如果长度大于 1,我们 return 显示对话框并发出所选项目的辅助方法,否则只发出第一个 (only) 项目。请注意,我们用 of
包装了普通值,因为在 switchMap 中,我们需要 return 可观察。
无论哪种情况,您的订阅回调都会发出和接收所需的项目。
我正在调用一个 API 服务,其中 returns 一个 Observable - 包含一个元素数组。
apiMethod(input: Input): Observable<ResultElement[]>
由此我一直在选择数组的第一个元素,并订阅它。然后使用该元素路由到另一个页面,如下所示:
this.apiService
.apiMethod(input)
.pipe(map((results) => results[0])
.subscribe(
(result) => {
return this.router.navigate('elements/', result.id)
}
)
这很好用。
问题是,我不想只使用第一个元素,我想要一个 MatDialog 或其他类似的弹出窗口,让用户选择选择哪个元素,然后路由到正确的那个。
如果列表仅包含一个元素,则不应显示对话框,并且应立即路由用户。
我试图在 .pipe(map())
函数中打开一个对话框,但是 subscribe()
在我得到用户的回答之前发生,导致它失败。而且我不确定这是否是正确的方法。你们会如何解决这个问题?
编辑 最终完成了@BizzyBob 建议的部分工作:
在 API 调用中将地图更改为 switchmap,以这种方式进行:
this.apiService
.apiMethod(input)
.pipe(switchMap((results) => this.mapToSingle(results)
.subscribe(
(result) => {
return this.router.navigate('elements/', result.id)
}
)
mapToSingle(ResultElement[])
是这样的:
private mapToSingle(results: ResultElement[]): Observable<ResultElement> {
if (result.length === 1){
return of(results[0]);
}
const dialogConfig = new MatDialogConfig<ResultElement[]>();
dialogConfig.data = results;
const dialogRef = this.dialog.open(ResultDialogComponent, dialogConfig);
return dialogRef.afterClosed();
}
我会用下面的方法解决:
- 通过订阅获取数据(不使用管道)。并将此数据保存在组件变量中
options: any;
this.apiService
.apiMethod(input)
.subscribe(
(result) => {
if (result.length === 1) {
this.router.navigate([result[0]]);
return;
}
options = result;
}
)
- 在模式上使用 ngIf(条件是选项数组的长度 > 0 在接收到数据时显示具有不同选择的组件
<modal-component *ngIf="options.length > 0"></modal-component>
- 当用户(单击)您的模式内的选项时,使用路由器进行重定向。
html
<div (click)="redirect(value)">option 1</div>
ts
redirect(value) {
this.router.navigate([value]);
}
那将是最直接的
两个可能的选择:
- 通过用户输入或使用一个元素获得 api 结果的副作用,为所选结果设置一个“下一个”主题。
- 跟踪组件的总体状态并在状态中设置 selectedResult 时做出适当响应。
下面的示例是使用 Observable 跟踪组件状态的草图。
- 有两个输入流进入状态,来自api的结果和用于选择结果的用户输入。
- 每个流都被转换成一个会修改整体状态的 reducer 函数。
- UI 应该通过异步管道订阅此状态,在适当的时候显示模态,并通过 Subjects 从事件更新更新状态。
- 当 selectedResult 有值时,重定向应该影响状态的改变。
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));
}
我最近经常使用这种模式。这使得状态的动作和属性的数量很容易增长。
我会创建一个 DialogComponent
,它将选项列表作为输入,并在它关闭时发出所选项目。
然后,创建一个辅助方法(可以称之为 promptUser
),它只是 return 一个发出选定值的可观察对象:
this.apiService.apiMethod(input)
.pipe(
switchMap(results => results.length > 1
? this.promptUser(results)
: of(results[0])
)
)
.subscribe(
result => this.router.navigate('elements/', result.id)
);
这里我们简单地使用 switchMap
到 return 一个发出正确项目的 Observable。如果长度大于 1,我们 return 显示对话框并发出所选项目的辅助方法,否则只发出第一个 (only) 项目。请注意,我们用 of
包装了普通值,因为在 switchMap 中,我们需要 return 可观察。
无论哪种情况,您的订阅回调都会发出和接收所需的项目。