【问题标题】:Angular prevent recreation of elementsAngular 阻止重新创建元素
【发布时间】:2021-06-08 21:01:26
【问题描述】:

所以我有一个组件可以加载带有动画的 div。 div 是根据数据源显示的。

*注意:在示例中我使用了很多<any>,那是因为我还没有决定模型。

apiService.ts

dataArray: Observable<Array<any>>;

constructor(){
   this.getUpdateData();
   setInterval(()=> this.getUpdateData(), 1000);
}

getUpdateData(){
    this.httpClientCall()
    .subscribe((response: any) => {
      this.dataArray = response;
    });
  }

component.html

<div class="panels" *ngFor="let data of apiService.dataArray">
    <div class="panel-that-has-animation">
        {{ data.some_value_that_can_be_updated }}
    </div>
</div>

简单分解:我每分钟从远程位置提取数据,并让响应为dataArray 中的新数据。

我遇到的问题是,在每次更新时,整个panels div 的内容都会被替换。 我宁愿只更新值而不是重新渲染整个 div。

数组本身由对象组成,我真正喜欢做的是更新数组中的一个对象属性,而不是替换整个对象数组。更确切;比较两个数组,检查对象的属性是否存在差异。

例子:

[ 
 0: {id: 1, name: a, group: 'a'},
 1: {id: 2, name: b, group: 'b'},
 2: {id: 3, name: c, group: 'c'},
]

新数据(来自 httpClient):

[ 
 0: {id: 1, name: a, group: 'b'},
 1: {id: 2, name: b, group: 'b'},
 2: {id: 3, name: c, group: 'c'},
]

在示例中,我想更新数组中的第一个对象,因为组字符串已更改,而不是替换整个对象数组。

我永远感激解决方案的原因/方式,而不仅仅是解决此问题的代码。 提前谢谢!

【问题讨论】:

  • this.dataArray = [...new Set([ ...(this.dataArray || []), ...response]) ] 这可能会解决您的问题。
  • trackBy 结构指令的 trackBy 函数可能是您正在寻找的。 stackoverflow.com/questions/42108217/…
  • @AdarshMohan 这给出了多个错误:Type 'any[]' is missing the following properties from type 'Observable&lt;any[]&gt;':Type 'Observable&lt;any[]&gt; | undefined[]' must have a '[Symbol.iterator]()' method that returns an iterator. 你能解释一下这是做什么的吗?如果我了解它的作用,我可能会对其进行调整,使其适合我的目的。
  • 它的作用是创建当前和前一个数组的平面数组,然后创建一个唯一的集合

标签: javascript html arrays angular observable


【解决方案1】:

*ngFor 可以利用trackBy 函数将数组元素与DOM 元素相关联。这允许 Angular 更有效地更新 DOM,因为它不会再销毁和重新创建所有项目,而只会创建新项目。

只需在控制器中创建一个小函数:

trackById = (index: number, item: Item) => item.id;

然后像这样将它添加到您的*ngFor

<div class="panels" *ngFor="let data of apiService.dataArray; trackBy: trackById">
    <div class="panel-that-has-animation">
        {{ data.some_value_that_can_be_updated }}
    </div>
</div>

现在您应该看到,随着源数据的更改,只会创建(动画)新项目,而现有项目将保留。


另外,这不是您的问题的一部分,但我想提一下,您可以从以下位置简化您的服务代码:

constructor(){
   this.getUpdateData();
   setInterval(()=> this.getUpdateData(), 1000);
}

getUpdateData(){
    this.httpClientCall()
    .subscribe((response: any) => {
      this.dataArray = response;
    });
  }

收件人:

dataArray$: Observable<Array<any>> = timer(0, 1000).pipe(
    switchMapTo(this.httpClientCall())
);

这还有一个额外的好处是懒惰;即 - 如果dataArray$ 没有订阅者,您将不会轮询服务器。

【讨论】:

  • trackBy: 绝对是我需要的!谢谢你的详细解释!
猜你喜欢
  • 2020-03-17
  • 1970-01-01
  • 1970-01-01
  • 2018-08-24
  • 1970-01-01
  • 1970-01-01
  • 2018-03-27
  • 2019-10-21
  • 2016-07-30
相关资源
最近更新 更多