【问题标题】:Angular 8 form controls freezing when list is loading加载列表时,Angular 8表单控制冻结
【发布时间】:2019-11-10 10:43:57
【问题描述】:

嗨,我正面临一个角度问题,比如我的页面具有基本的角度形式以及两个独立的组件,它们基本上从 API 加载列表,如 cmets[500+records]、posts[500+records]。

问题:

当列表加载时尝试向表单输入值时,基本上它无法执行键/检查​​/取消选中/选择事件

cmets,posts loaded only页面允许在表单中做事

这是例外行为吗?

我只是想解耦过程,比如加载列表(posts,cmets)不应该影响要输入的角度表单/html表单。

请帮我解决这个问题。

我的 stackblitz 代码如:https://stackblitz.com/edit/angular-ngfor-issue

chrome[only large data set]/IE11 中可重现。

尝试使用trackBy, async pipe 也没有任何帮助

【问题讨论】:

  • 无法重现。我的网络速度减慢到 50kbps 并检查,但我可以访问表单。列表加载不会影响您的表单。
  • @chintankotadiya 你可以下载项目并尝试在本地运行在IE11中打开一个APP。该问题将是可重现的。
  • 您是否取消注释 IEpolyfills.ts 的依赖关系?
  • @chintankotadiya 问题将在两个浏览器中重现。就像在 chrome 中一样,当记录太高时,它会清晰可见 1000+ 。但在 IE 中,它甚至会发生 500 多条记录。

标签: html angular angular5 angular7 angular8


【解决方案1】:

我无法重现您的 StackBlitz 中的冻结。我相信它可能是由于在该站点上使用加载指示器处理代码的方式而被隐藏的。但是,从您的描述看来,问题在于 DOM 中 500 多个项目的实际呈现(如果冻结)。尝试查看 Angular 更改检测策略:https://blog.ninja-squad.com/2018/09/27/angular-performances-part-4/

我会尝试将两个列表组件的更改检测切换到 OnPush 以查看是否存在差异。

【讨论】:

  • 你可以下载项目并尝试在本地运行在IE11中打开一个APP。该问题将是可重现的。
【解决方案2】:

我能够在 IE 中重现这种滞后。

我重构了您的代码以提高性能。如果您正在处理大型数据集并渲染大型列表,除了trackBy,您还应该考虑使用ChangeDetectionStrategy.OnPush 作为您的changeDetectionStrategy

重构后的代码如下所示:

import { Component, ChangeDetectionStrategy } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Component({
  selector: 'app-comments',
  templateUrl: './comments.component.html',
  styleUrls: ['./comments.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CommentsComponent {
  comments$: Observable<Array<any>> = this.http.get(`https://jsonplaceholder.typicode.com/comments`);

  constructor(private readonly http: HttpClient) { }

  trackyFn(item) {
    return item.id;
  }

}

模板:

<h1>Comments</h1>
<div class="row">
    <div class="col-md-12" style="height: 250px; overflow:scroll">
        <table class="table table-hover">
            <thead>
                <tr>
                    <th>Id</th>
                    <th>Name</th>
                    <th>Email</th>
                    <th>Body</th>
                </tr>
            </thead>
            <tbody>
                <tr *ngFor="let comment of comments$ | async; trackBy:trackyFn;">
                    <td>{{comment.id}}</td>
                    <td>{{comment.name}}</td>
                    <td>{{comment.email}}</td>
                    <td>{{comment.Body}}</td>
                </tr>
            </tbody>
        </table>
    </div>
</div>

同样,您可以重构PostsComponent

还有你的 AppComponent:

import { Component, ChangeDetectionStrategy } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {
  name = 'Angular';
  registerForm: FormGroup;

  constructor(private readonly formBuilder: FormBuilder) { }

  ngOnInit() {
    this.registerForm = this.formBuilder.group({
      firstName: ['', Validators.required],
      lastName: ['', Validators.required],
      termsAgreed: [false],
      gender: ['male'],
      std: [10]
    });
  }

}

我所做的更改:

  1. 在所有组件中使用了changeDetection: ChangeDetectionStrategy.OnPush,。 - 随着 Angular 执行更少的 CD 周期,提高性能的主要因素。
  2. 在模板中使用async,而不是分别从ObservableSubscription 手动使用subscribeing 和unsubscribeing。 - 只是为了让代码更简洁。

如果您是 Windows 用户,要查看性能是否得到改进,请在文本表单字段中按住键盘上的任意键,然后查看输入是否能顺利反映。


这里有一个Working Sample StackBlitz 供您参考。

【讨论】:

  • 这是一个不错的解决方案!但是,如果我想在加载过程中显示加载器/微调器如何实现这一点,因为我不再可以在组件中使用 .subscribe()
  • 我会为此使用通用的 HttpInterceptor。看看如何实现一个here
  • 由于异步选项可用并且更改检测策略设置为 OnPush,因此对于特定模板,您可以输入 *ngIf="(cmets$ | async).length > 0; else showLoading"。最好在
    然后使用
猜你喜欢
  • 2013-03-04
  • 1970-01-01
  • 2020-07-12
  • 1970-01-01
  • 1970-01-01
  • 2012-02-03
  • 2012-03-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多