Angular:如何订阅@Input更改

时间:2017-10-19 10:10:23

标签: angular

我正在尝试创建一个角度组件,它使用提供的对象数组呈现html表。

我已实施OnChanges来检测对@Input的更改,但它似乎无效。

为了测试,我使用setInterval添加一些数据,但它没有反映在子组件中。

这是我到目前为止的代码,

NG-table.component.ts:

export class NgTableComponent implements OnInit, OnChanges {

    @Input() data: any[];

    private columns: string[];
    private rows: string[][];

    constructor() {
        this.columns = [];
        this.rows = [];
    }

    ngOnInit() {
    }

    ngOnChanges(changes: SimpleChanges) {
        console.log(changes);
        if (changes.data) {
            this.extractRowsAndColumns(this.data);
        }
    }

    extractRowsAndColumns(objArray: any[]): void {
        const colSet = new Set<string>();
        for (let i = 0; i < objArray.length; i++) {
            const keys = Object.keys(objArray[i]);
            for (let j = 0; j < keys.length; j++) {
                colSet.add(keys[j]);
            }
        }
        this.columns = Array.from(colSet);

        for (let i = 0; i < objArray.length; i++) {
            const obj = objArray[i];
            const row = [];
            for (let j = 0; j < this.columns.length; j++) {
                if (obj.hasOwnProperty(this.columns[j])) {
                    row.push(obj[this.columns[j]]);
                } else {
                    row.push(null);
                }
            }
            this.rows.push(row);
        }
    }
}

NG-table.component.html:

<div>
    <table class="ngtable">
        <tr>
            <th *ngFor="let col of columns">
                {{col}}
            </th>
        </tr>
        <tr *ngFor="let row of rows">
            <td *ngFor="let cell of row">{{cell}}</td>
        </tr>
    </table>
</div>

我在app.component

中使用上面的组件

app.component.ts:

export class AppComponent {
  timer: any;
  count = 0;
  constructor() {
    const o: any = {
      'id': 1,
      'name': 'Jeanette',
      'last_name': 'Penddreth',
      'email': 'jpenddreth0@census.gov',
      'gender': 'Female',
      'ip_address': '26.58.193.2'
    };
    this.timer = setInterval(() => {
      this.data.push(o);
      console.log(this.data.length);
      if ( this.count++ === 5) {
        clearInterval(this.timer);
      }
    }, 1000 * 1);
  }

  data = [{
    'id': 1,
    'name': 'Jeanette',
    'last_name': 'Penddreth',
    'email': 'jpenddreth0@census.gov',
    'gender': 'Female',
    'ip_address': '26.58.193.2'
  }, {
    'id': 2,
    'name': 'Giavani',
    'last_name': 'Frediani',
    'email': 'gfrediani1@senate.gov',
    'gender': 'Male',
    'ip_address': '229.179.4.212'
  }, {
    'id': 3,
    'name': 'Noell',
    'last_name': 'Bea',
    'email': 'nbea2@imageshack.us',
    'gender': 'Female',
    'ip_address': '180.66.162.255'
  }, {
    'id': 4,
    'name': 'Willard',
    'last_name': 'Valek',
    'email': 'wvalek3@vk.com',
    'gender': 'Male',
    'ip_address': '67.76.188.26'
  }];
}

app.component.html:

<app-ng-table [data]="data"></app-ng-table>

如何在@Input更改时更新组件?

更新:我创建了一个plunkr来证明这一点:https://plnkr.co/edit/szz1SNooQ1vIZhnFgiys?p=preview

5 个答案:

答案 0 :(得分:2)

作为问题的简单解决方案,您可以检测@Input中的ngOnChanges更改,如下所示:

ngOnChanges(changes: SimpleChanges) {   
   for (let propName in changes) {
      // when your @Input value is changed  
      if(propName === "yourInputName"){
         // update the component here 
      }
   }
}

希望有所帮助:)

答案 1 :(得分:2)

只需进行@Input()双向绑定......

_data;
@Input() set data(val) {
  this._data = val;
}
get data() {
  return this._data;
}

答案 2 :(得分:1)

之前我遇到过同样的问题; ngOnChanges方法仅侦听数据类型==!数组的更改。

解释(ngOnChanges not firing for nested object):

  

在更改检测期间,当Angular检查组件的输入时   更改属性,它使用(基本上)===进行脏检查。   对于数组,这意味着对数组引用(仅)进行脏检查。   由于rawLapsData数组引用没有改变,ngOnChanges()   将不会被召唤。

答案 3 :(得分:0)

正如TimHovius所说,angular只是在进行参考检查。由于您要推送到同一个数组,因此ng-table.component未检测到更改(对输入的引用仍然相同)。您可以做的一件事是创建数组的浅表副本。

addItem(): void {
    this.data.push(this.data[this.data.length-1]);
    // create shallow copy of array, since this is a new array (and new reference) ngOnChanges hook of the ng-table.component will fire
    this.data = this.data.slice(0);
}

现在ng-table.component将检测到输入已更改并触发ngOnChanges

这是一个演示此(https://plnkr.co/edit/2tdMEA9PLc2TEL4Gy4Lp?p=preview

的plunkr

答案 4 :(得分:0)

您需要为其分配新对象。大部分都可以通过Object.assign

来完成

在你的例子中,你只需要改变几行,休息就可以顺利进行。

...
let data:[] = this.data;
data.push(o);
this.data = Object.assign([], data);
...