简体   繁体   English

Angular:如何订阅@Input更改

[英]Angular: How to subscribe to @Input changes

I'm trying to create a angular component, which renders a html table using the provided object array. 我正在尝试创建一个角度组件,它使用提供的对象数组呈现html表。

I have implemented OnChanges to detect changes to the @Input , it doesn't seem to work though. 我已经实现了OnChanges来检测@Input更改,但它似乎不起作用。

For testing, I'm using setInterval to add some data, but It's not getting reflected in the child component. 为了测试,我使用setInterval来添加一些数据,但它没有反映在子组件中。

This it the code I have so far, 这是我到目前为止的代码,

ng-table.component.ts: 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: 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>

I'm using the above component in app.component 我在app.component中使用上面的组件

app.component.ts: 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.component.html:

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

How can I make the component update when @Input changes? @Input更改时,如何更新组件?

UPDATE: I have created a plunkr demonstrating this: https://plnkr.co/edit/szz1SNooQ1vIZhnFgiys?p=preview 更新:我创建了一个plunkr来证明这一点: https ://plnkr.co/edit/szz1SNooQ1vIZhnFgiys?p = preview

as a simple solution to your problem , you can detect @Input changes in ngOnChanges like this : 作为一个简单的解决你的问题,你可以检测@Input的变化ngOnChanges这样的:

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

Hope it helps :) 希望能帮助到你 :)

Just make your @Input() two-way binding... 只需将@Input()双向绑定...

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

I had the same problem before; 我之前遇到过同样的问题; the ngOnChanges method listens only to changes on datatypes ==! ngOnChanges方法仅侦听数据类型==!更改==! array. 阵列。

Explanation ( ngOnChanges not firing for nested object ): 解释( 对于嵌套对象,不触发ngOnChanges ):

During change detection, when Angular checks components' input properties for change, it uses (essentially) === for dirty checking. 在更改检测期间,当Angular检查组件的输入属性以进行更改时,它使用(基本上)===进行脏检查。 For arrays, this means the array references (only) are dirty checked. 对于数组,这意味着对数组引用(仅)进行脏检查。 Since the rawLapsData array reference isn't changing, ngOnChanges() will not be called. 由于rawLapsData数组引用未更改,因此不会调用ngOnChanges()。

As TimHovius stated, angular is only doing a reference check. 正如TimHovius所说,棱角分析只是做参考检查。 Since you are pushing to the same array, the ng-table.component is not detecting a change (the reference to the input is still the same). 由于您要推送到同一个数组,因此ng-table.component未检测到更改(对输入的引用仍然相同)。 One thing you can do is to create a shallow copy of the array. 您可以做的一件事是创建数组的浅表副本。

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);
}

Now ng-table.component will detect that the input has changed and fire ngOnChanges 现在ng-table.component将检测输入已更改并触发ngOnChanges

Here is a plunkr demoing this ( https://plnkr.co/edit/2tdMEA9PLc2TEL4Gy4Lp?p=preview ) 这是一个演示这个的plunkr( https://plnkr.co/edit/2tdMEA9PLc2TEL4Gy4Lp?p=preview

You need to assign new object to it. 您需要为其分配新对象。 Mostly can be done by Object.assign 大部分都可以通过Object.assign完成

In your example, you just need to change few line and rest will work smooth. 在你的例子中,你只需要改变几行,休息就可以顺利进行。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM