如何在 Angular 中继续之前等待来自服务的新数据
How to wait for new data from service before proceeding in Angular
我有两个使用服务共享数据的组件:
export class ShareDataService {
msg: BehaviorSubject<string>;
constructor(
) {
this.msg = new BehaviorSubject("Default Message")
}
changeMessage(message: string) {
this.msg.next(message)
}
}
第一个组件用作路由器,当我单击一个名称时,它会使用其 ID 重定向到该名称的配置文件。我导入上面创建的共享数据服务,当单击名称时它会触发 de sendData() 函数,该函数获取被单击元素的 ID 并将其作为参数传递给服务 changeMessagge() 函数:
constructor(
private _data: ShareDataService
) { }
message: string = "";
ngOnInit(): void {
this._data.msg.subscribe(new_msg => this.message = new_msg)
}
sendData() {
var self = this
$("ul.users-list").on("click", ".user", function(event) {
self._data.changeMessage(event.target.id)
});
}
}
之后,当它重定向到新组件时,这个新组件也从服务中导入数据:
message: string = "";
constructor(
private _http: HttpClient,
private _data: ShareDataService,
private _router: Router
) { }
async ngOnInit() {
this._data.msg.subscribe(new_msg => this.message = new_msg)
await new Promise(r => setTimeout(r, 1)); // Sleeps 1ms so it can load message
if (this.message === "Default Message") { // Returns to landing if no user loaded
this._router.navigateByUrl("/landing");
return
}
this._http.get<UserInterface>(`https://jsonplaceholder.typicode.com/users/${this.message}`)
.subscribe((data: UserInterface) => this.user = data)
}
如您所见,它订阅了该服务并获取了 messagge 的值,当我在另一个组件上单击名称时,该值应该已更改。问题是,它首先没有检测到变化,我必须使用新的 Promise() 函数让它休眠 1 毫秒,以便它可以从服务加载新的 messagge 值,然后继续。有什么办法可以让它等待订阅完成加载新消息而无需使用 Promise 1 毫秒?已经尝试在分配消息后将代码放入订阅中。
我看到多个问题
- 变量
this.message
被异步赋值。发送 HTTP 请求时,尚未为其分配值。您需要使用像 switchMap
这样的高阶映射运算符来从一个可观察对象映射到另一个。
import { switchMap } from 'rxjs/operators';
this._data.msg.pipe(
switchMap(message =>
this._http.get<UserInterface>(`https://jsonplaceholder.typicode.com/users/${message}`)
)
).subscribe((data: UserInterface) => this.user = data)
您可以查看我的 post ,了解有关处理多个相互依赖的可观察量的简要信息。
await new Promise(r => setTimeout(r, 1));
看起来不雅,但超时时间很小。有了上面的映射运算符,就不再需要它了。
避免在 Angular 中使用 jQuery。 jQuery 中的几乎所有内容都可以直接在 Angular 中完成。混合使用它们可能会导致以后进行维护。
更新:return有条件地观察
根据您的情况,您可以使用带有 new Observable()
构造的 RxJS iif
函数来 return HTTP 请求或执行其他操作并根据条件关闭可观察对象。
尝试以下方法
import { iif, EMPTY, Observable } from 'rxjs';
import { switchMap } from 'rxjs/operators';
this._data.msg.pipe(
switchMap(message =>
iif(
() => message === "Default Message",
new Observable(subscriber => {
this._router.navigateByUrl("/landing");
subscriber.complete();
}),
this._http.get<UserInterface>(`https://jsonplaceholder.typicode.com/users/${message}`)
)
)
).subscribe((data: UserInterface) => this.user = data)
我有两个使用服务共享数据的组件:
export class ShareDataService {
msg: BehaviorSubject<string>;
constructor(
) {
this.msg = new BehaviorSubject("Default Message")
}
changeMessage(message: string) {
this.msg.next(message)
}
}
第一个组件用作路由器,当我单击一个名称时,它会使用其 ID 重定向到该名称的配置文件。我导入上面创建的共享数据服务,当单击名称时它会触发 de sendData() 函数,该函数获取被单击元素的 ID 并将其作为参数传递给服务 changeMessagge() 函数:
constructor(
private _data: ShareDataService
) { }
message: string = "";
ngOnInit(): void {
this._data.msg.subscribe(new_msg => this.message = new_msg)
}
sendData() {
var self = this
$("ul.users-list").on("click", ".user", function(event) {
self._data.changeMessage(event.target.id)
});
}
}
之后,当它重定向到新组件时,这个新组件也从服务中导入数据:
message: string = "";
constructor(
private _http: HttpClient,
private _data: ShareDataService,
private _router: Router
) { }
async ngOnInit() {
this._data.msg.subscribe(new_msg => this.message = new_msg)
await new Promise(r => setTimeout(r, 1)); // Sleeps 1ms so it can load message
if (this.message === "Default Message") { // Returns to landing if no user loaded
this._router.navigateByUrl("/landing");
return
}
this._http.get<UserInterface>(`https://jsonplaceholder.typicode.com/users/${this.message}`)
.subscribe((data: UserInterface) => this.user = data)
}
如您所见,它订阅了该服务并获取了 messagge 的值,当我在另一个组件上单击名称时,该值应该已更改。问题是,它首先没有检测到变化,我必须使用新的 Promise() 函数让它休眠 1 毫秒,以便它可以从服务加载新的 messagge 值,然后继续。有什么办法可以让它等待订阅完成加载新消息而无需使用 Promise 1 毫秒?已经尝试在分配消息后将代码放入订阅中。
我看到多个问题
- 变量
this.message
被异步赋值。发送 HTTP 请求时,尚未为其分配值。您需要使用像switchMap
这样的高阶映射运算符来从一个可观察对象映射到另一个。
import { switchMap } from 'rxjs/operators';
this._data.msg.pipe(
switchMap(message =>
this._http.get<UserInterface>(`https://jsonplaceholder.typicode.com/users/${message}`)
)
).subscribe((data: UserInterface) => this.user = data)
您可以查看我的 post
await new Promise(r => setTimeout(r, 1));
看起来不雅,但超时时间很小。有了上面的映射运算符,就不再需要它了。避免在 Angular 中使用 jQuery。 jQuery 中的几乎所有内容都可以直接在 Angular 中完成。混合使用它们可能会导致以后进行维护。
更新:return有条件地观察
根据您的情况,您可以使用带有 new Observable()
构造的 RxJS iif
函数来 return HTTP 请求或执行其他操作并根据条件关闭可观察对象。
尝试以下方法
import { iif, EMPTY, Observable } from 'rxjs';
import { switchMap } from 'rxjs/operators';
this._data.msg.pipe(
switchMap(message =>
iif(
() => message === "Default Message",
new Observable(subscriber => {
this._router.navigateByUrl("/landing");
subscriber.complete();
}),
this._http.get<UserInterface>(`https://jsonplaceholder.typicode.com/users/${message}`)
)
)
).subscribe((data: UserInterface) => this.user = data)