Angular 默认通过引用比较对象
你快到了。问题是你的select
得到一个列表option
s 引用Post
s 作为一部分ngFor
。现在要找出哪个option
当前已选择,Angular 会比较每个post
当前值为的对象selectedPost$ | async
.
默认情况下,完成的方法是使用===
操作员。这===
运算符按值比较基元,但按引用比较对象。例子:
console.log('a' === 'a');
const obj = {'a': 'b'};
const obj2 = obj;
console.log(obj === obj2);
console.log(obj === {'a': 'b'});
所以为了post
算作同一个帖子selectedPost$ | async
,它们必须是实际相同的对象,而不仅仅是看起来相同的对象。
您实际上检索同一帖子的多个副本,而不仅仅是一个帖子
现在情况并非如此:当您使用async
管道,在更改检测期间,可能会发生从 API 重新加载帖子的情况。当您查看浏览器的网络选项卡时,您实际上可以看到有三个请求:
所有请求的响应负载都是相同的,但是Post
对象被返回三次,它们被存储在内存中三次。 JavaScript 无法知道它们实际上是相同的,并且===
比较回报false
.
解决方案:提供您自己的解决方案compareWith
功能
你怎么解决这个问题?你可以帮忙Angular比较一下Post
正确地在你的对象select
。你只需要问自己这个问题:我怎么知道两个Post
对象实际上是同一个对象?在这种情况下,答案是:当它们具有相同的 ID 时。
现在,您可以为 Angular 编写自己的指令来比较对象或您的选择:只需添加一个compareWith
输入到选择:
<select [ngModel]="selectedPost$ | async"
(change)="onSelected($event.target.value)"
[compareWith]="comparePosts"
>
现在 Angular 知道使用一种名为comparePosts
比较两个帖子。现在这个方法看起来怎么样?例如这样:
comparePosts(p1: Post, p2: Post) {
return p1.id === p2.id;
}
现在 Angular 知道如何正确比较两个Post
对象,你的问题就解决了。
PS:请务必写一个更好的comparePosts
方法比我做的好,例如也处理得当undefined
and null
values.