我在我的angular(7)应用程序中使用BehaviorSubject遇到了奇怪的行为。
我创建了一个使用一些剩余呼叫的服务。要显示代码中发生的事情,您在这里:
export class MyService {
private dataFromServer = new BehaviorSubject<IDataFromServer[]>(null);
constructor(private http: HttpClient) { }
getAll(): Observable<IDataFromServer[]> {
this.http.get<IDataFromServer[]>('/api/rest')
.pipe(
tap(data => this.dataFromServer.next(data))
);
}
return this.dataFromServer.asObservable();
}
到目前为止,一切都很好。当我需要使用此服务时,我订阅了像
这样的getAll()方法this.myService.getAll().subscribe(console.log);
并将数据打印到控制台。
现在我必须将前端的数据添加到其余的api
export class MyService {
private dataFromServer = new BehaviorSubject<IDataFromServer[]>(null);
// snip...
add(item: IDataFromServer): Observable<any> {
return this.http.post<IDataFromServer>('/api/manage', item).pipe(
tap(data => {
let internal = this.dataFromServer.getValue();
if (!internal) {
internal = new Array<IDataFromServer>();
}
internal.push(material);
this.dataFromServer.next(internal);
})
);
}
}
这是麻烦开始的地方。上面的订阅是第一次打印,但没有收到next()触发的新数据。
让我感到困惑的是,如果我在浏览器上单击了刷新,而没有更改代码的任何行,则每次单击next()时,订阅都将重新生效。
我显然做错了事,但我不明白为什么在哪里。
感谢您的帮助。
答案 0 :(得分:3)
问题是您在#year {
width:150px;
}
内致电#year option{
width:150px;
}
,但没有人订阅。
您提到的第一个日志必须为this.http.get<IDataFromServer[]>('/api/rest')
,因为您将getAll
初始化为空。
您需要做的就是简单地从null
返回BehaviorSubject
,以便任何人调用此方法并订阅该方法都会触发http调用。另外,http.get
将确保您在getAll
中的数据将被更新。
tap
答案 1 :(得分:1)
尽管您没有包括调用add
函数的部分,但我可以肯定您不订阅该函数的结果。
您可能会有一行类似这样的代码
myService.add(myItem);
现在,这将返回一个Observable。但是请注意,如果没有人订阅该Observable,则不会触发连接的管道。
因此,您有两种解决方案。
首先:不要使用tap
,而是要订阅。我几乎可以确定这就是您想要的。它是这样的:
add(item: IDataFromServer): void {
this.http.post<IDataFromServer>('/api/manage', item)
.subscribe(data => {
let internal = this.dataFromServer.getValue();
if (!internal) {
internal = new Array<IDataFromServer>();
}
internal.push(material);
this.dataFromServer.next(internal);
}
);
}
第二个:订阅add
的结果。像这样:
myService.add(myItem).subscribe();
该问题是由对Observable的常见误解引起的。 Maybe this post helps。
答案 2 :(得分:1)
连同有关为什么您的解决方案不起作用的好答案,我将对您的方法有何不足之处加我的看法。
据我所知,您正在尝试从服务中公开一个可观察的对象,将其用于每个REST调用,从而允许视图与数据更新登录分离并重用数据可视化逻辑(即,它们仅需要显示每次更新数据时,都会调用相同的逻辑。)
问题在于httpClient
的可观察对象是惰性的,实际上只有有人订阅时才发送请求。
我做过同样的事情,通常要做的是在服务中隐藏http调用并在内部订阅。借用您的课程,看起来像这样:
export class MyService {
private dataFromServer = new BehaviorSubject<IDataFromServer[]>(null);
constructor(private http: HttpClient) { }
getAll(): Observable<IDataFromServer[]> {
this.http.get<IDataFromServer[]>('/api/rest')
.subscribe(data => this.dataFromServer.next(data));
return this.dataFromServer.asObservable();
}
add(item: IDataFromServer): Observable<any> {
return this.http.post<IDataFromServer>('/api/manage', item)
.subscribe(data => this.dataFromServer.next(data));
}
}
我还假设您的端点遵循REST原则,因此/api/manage
路径将返回使用新添加的数据更新的完整列表作为响应,就像在POST之后返回对/api/rest/
的调用一样打电话。