【问题标题】:Why is input attribute called hundreds of times when evaluating a function为什么在评估函数时输入属性被调用数百次
【发布时间】:2018-11-16 04:00:45
【问题描述】:

我通过控制访问使用属性来检查是否应该启用或禁用字段。

所以我有这样的东西:

<input matInput type="text" #name="ngModel" name="application.name" [ngModel]="application?.name" (ngModelChange)="application.name=$event"
              placeholder="Nom de l'application" required [disabled]="isDisabled([permissions.applications.any.update, permissions.applications.own.update], 'name')"[appUnique]="application" [listElem]="applications" key="name" maxlength="255">

当显示输入时,isDisabled 函数会被调用数百次,并且表单上的每个操作都会触发 12 或 32 次额外调用。

这会导致我的浏览器死机。

知道为什么会发生这种行为吗?是 ZoneJS 造成的吗?

如何只调用这个函数?

编辑:指令实现

/**
 * Check if the component should be disabled
 */
@Directive({
  selector: "[appIsDisabled]"
})
export class IsDisabledDirective implements OnInit {
  // Listof permission to check 
  @Input("appIsDisabled") permissions: PermissionInterface[];
  // The resource id to be access
  @Input() resourceId: number;
  // The resource type to be access
  @Input() resourceType: string;
   // Attribute to be check(eg: name, firstname... for a user resource)
  @Input() attribute: string;
  constructor(private authService: AuthService, private el: ElementRef, private utilsService: UtilsService, private renderer: Renderer2) {
  }

  ngOnInit() {
    if (!this.authService.hasPermission(this.permissions, this.resourceId, this.resourceType, this.attribute)) {
      this.renderer.setAttribute(this.el.nativeElement, "disabled", "disabled");
    }

  }
}

【问题讨论】:

  • 有一些关于这种行为的好文章:blog.appverse.io/…
  • 好的,我知道角循环,但不知道它也适用于属性。文本文件。我会找到另一种解决方案来控制输入的禁用状态。如果有人提出建议,那就太好了

标签: javascript angular forms typescript disabled-input


【解决方案1】:

最好不要对方法进行属性绑定,以免过于频繁地检查状态。

以下是我的建议:

  1. 使用 RxJS 来跟踪更改。
    • 尝试检测您的 permissions.applications.any.update 更改并包装到 Observable 中。您可以通过组件中的 ngOnInit 挂钩订阅它。
  2. 使用 Pure Pipe 检测变化。
    • 尝试将您的 isDisabled 方法移动到纯管道组件。
  3. 使用 setInterval 定期检查状态变化。

【讨论】:

  • 这不适用于我的情况。状态总是一样的。在用户连接上检索权限。我更改我的代码以使用添加禁用属性的指令。现在我需要找到一种方法来告诉 mat-form-field 考虑这种变化。
  • 即使您使用指令,您仍然必须面对变更检测问题。你能分享一下你的isDisabled 实现吗?
  • 我测试了一下,指令的onInit中的方法只调用了一次。输入获取它的禁用属性,但这不适用于视图,因为 Mat-form-field 没有检测到机会。我更新了我的问题以发布我的指令
  • @Scandinave 你的this.authService.hasPermission() 是否只需要在组件初始化后执行一次?
  • 当使用指令时是。
【解决方案2】:

简短的回答是您的方法是由角度变化检测算法执行的。 Angular 会扫描每个绑定以检测更改并采取相应的行动,并且它会经常这样做,并且每个事件可能会发生多次。您需要了解this process 以及如何使用minimize it。这是一个大主题,在 SO 答案中详细介绍是不合适的,但参考文章中的三个提示是:

拥有更少的 DOM。这是拼图中至关重要的一块。如果 DOM 元素不可见,您应该使用 *ngIf 将它们从 DOM 中删除,而不是简单地使用 CSS 隐藏元素。俗话说,最快的代码是不运行的代码——最快的 DOM 是不存在的 DOM。

让你的表达更快。将复杂的计算移到 ngDoCheck 生命周期钩子中,并在您的视图中引用计算值。尽可能长时间地将结果缓存到复杂的计算中。

使用 OnPush 变化检测策略告诉 Angular 2 没有变化。这可以让您在大多数情况下跳过大部分应用程序的整个更改检测步骤。

【讨论】:

  • 我认为把东西放在ngDoCheck 生命周期钩子里不是一个好的选择。
【解决方案3】:

好的,我找到了解决问题的方法, 我预先计算了组件端所有字段的状态。 所以对于用户个人资料,这是我的功能:

 computesFieldsDisableState() {
    this.disabled = {
      thumbnails: !this.authService.hasPermission([this.permissions.profil.update], this.user.id, "user", "thumbnails"),
      name: !this.authService.hasPermission([this.permissions.profil.update], this.user.id, "user", "name"),
      firstname: !this.authService.hasPermission([this.permissions.profil.update], this.user.id, "user", "firstname"),
      password: !this.authService.hasPermission([this.permissions.profil.update], this.user.id, "user", "password"),
      email: !this.authService.hasPermission([this.permissions.profil.update], this.user.id, "user", "email"),
      roles: !this.authService.hasPermission([this.permissions.profil.update], this.user.id, "user", "roles"),
    };
  }

现在我只需要使用[disabled]="disabled.thumbnails" 来获取该字段的状态。

谢谢大家的回答。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-06
    • 1970-01-01
    • 2022-07-05
    • 2020-07-10
    • 1970-01-01
    相关资源
    最近更新 更多