Angular5模板绑定,不止一次调用回调函数

时间:2018-02-24 07:22:07

标签: angular angular5 angular-template

我尝试使用包含columns definition及其data array的结构化数据来实现网格组件。

每列的定义中都有一个callback函数,用于自定义显示该列的值。

在每个callback内部,它调用了一个console.log()来显示回调函数被调用的次数。

我不知道为什么回调函数在开始时调用了四次,two times事件在changeSort()事件被触发后!请告诉我。

我写了下表组件:

import { Component, OnInit, Input } from '@angular/core';

@Component({
  selector: 'app-table',
  templateUrl: './table.component.html',
  styleUrls: ['./table.component.css']
})
export class TableComponent implements OnInit {

  // @Input() public grid: {
  //   columns: any[],
  //   data: any[]
  // };

  public grid: any;

  constructor() {
    this.grid = {
      columns: [],
      data: [],
    };
  }

  ngOnInit() {
    this.grid = {
      data: [
        {
          desc: 'hello 1',
          header: 'my header 1'
        },
        {
          desc: 'hello 2',
          header: 'my header 2'
        },
        {
          desc: 'hello 3',
          header: 'my header 3'
        }
      ],
      columns: [
        {
          title: 'Description',
          field: 'desc',
          sortable: false,
          callback: (value) => this.myCallback1(value),
        },
        {
          title: 'Header',
          field: 'header',
          sortable: true,
          callback: (value) => this.myCallback2(value),
        },
      ],
    };
  }

  public changeSort(field) {
    console.log(field);
  }

  public myCallback1(value) {
    console.log('myCallback', value);
    return value + ' mc1';
  }

  public myCallback2(value) {
    console.log('myCallback2', value);
    return value + ' mc2';
  }

}

它的模板是:

<div class="table-responsive">
  <table class="table table-striped table-sm">
    <thead>
    <tr>
      <th>#</th>
      <th *ngFor="let col of grid.columns">
        <span (click)="changeSort(col)" *ngIf="col.sortable">{{col.title}}</span>
        <span *ngIf="!col.sortable">{{col.title}}</span>
      </th>
    </tr>
    </thead>
    <tbody>
    <tr *ngFor="let row of grid.data; let i = index">
      <td>{{i+1}}</td>
      <td *ngFor="let col of grid.columns">{{col.callback ? col.callback(row[col.field]) : row[col.field]}}</td>
    </tr>
    </tbody>
  </table>
</div>

这是开头的日志错误:

myCallback hello 1
myCallback2 my header 1
myCallback hello 2
myCallback2 my header 2
myCallback hello 3
myCallback2 my header 3
myCallback hello 1
myCallback2 my header 1
myCallback hello 2
myCallback2 my header 2
myCallback hello 3
myCallback2 my header 3
myCallback hello 1
myCallback2 my header 1
myCallback hello 2
myCallback2 my header 2
myCallback hello 3
myCallback2 my header 3
myCallback hello 1
myCallback2 my header 1
myCallback hello 2
myCallback2 my header 2
myCallback hello 3
myCallback2 my header 3

2 个答案:

答案 0 :(得分:5)

Angular处理模型和dom(组件和模板文件)之间的绑定。为此,应用程序勾选(更改检测周期)并检查是否有任何已更改的值,如果是,则 - >更新dom。

问题在于模板文件中有函数,每个循环角度调用函数来检查“值”是否已更改。

例如,如果我有一个只返回值的简单get函数,Angular需要运行它来检查实际上是否有变化。

{{ myValue() }} // in the template file

myValue() { return 10 } // in the component

这里有意义的是,angular必须调用每个函数来检查值是否已经改变。

解决方案(如果您不希望Angular不断调用您的函数)是实现ChangeDectionStrategy(https://angular.io/api/core/ChangeDetectionStrategy)。 有了这个,您可以告诉Angular您将处理更新,以及何时应该运行循环(仅适用于该组件)。

要在组件元数据中执行此操作,您将添加以下内容:

@Component({
  selector: 'app-table',
  templateUrl: './table.component.html',
  styleUrls: ['./table.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush // the new line
})

然后在构造函数中:

constructor(private changeDetectorRef: ChangeDetectorRef) {}

每当您进行更改时,您都可以调用 this.changeDetectorRef.markForCheck(); ,它将手动运行此组件的循环并在需要时更新dom。

我真的建议更多地阅读这个内容,因为这个主题太宽泛,不能在这篇文章中描述

答案 1 :(得分:0)

当你有一个模板绑定调用一个方法(这里是col.callback(row[col.field]))时,每次触发你的组件的变化检测时都会调用该方法(angular渲染你的组件的html,因此调用所有绑定的方法)方法)。因此你会看到控制台日志。并且因为该方法是在ngFor的模板中调用的,所以会为它的每个项目调用它。