2017-10-19 124 views
0

我想创建一个角度组件,它使用提供的对象数组呈现一个html表。Angular:如何订阅@Input变化

我已经实施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': '[email protected]', 
     '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': '[email protected]', 
    'gender': 'Female', 
    'ip_address': '26.58.193.2' 
    }, { 
    'id': 2, 
    'name': 'Giavani', 
    'last_name': 'Frediani', 
    'email': '[email protected]', 
    'gender': 'Male', 
    'ip_address': '229.179.4.212' 
    }, { 
    'id': 3, 
    'name': 'Noell', 
    'last_name': 'Bea', 
    'email': '[email protected]', 
    'gender': 'Female', 
    'ip_address': '180.66.162.255' 
    }, { 
    'id': 4, 
    'name': 'Willard', 
    'last_name': 'Valek', 
    'email': '[email protected]', 
    '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

+0

参照本[尝试的可观察输入* * answer **](https://stackoverflow.com/questions/44467336/observable-of-input-property/44467942#44467942) – Aravind

+0

有兴趣的人可以在这里看看完整的代码:https:// github .com/cyberpirate92/ngTable – cyberpirate92

回答

1

正如TimHovius所说,角度只做参考检查。由于您正在推送相同的数组,因此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

下面是一个plunkr demoing这个(https://plnkr.co/edit/2tdMEA9PLc2TEL4Gy4Lp?p=preview

+0

@ cyberpirate92忘了加我plnkr – LLai

+0

谢谢@LLai,浅拷贝作品。 我想知道是否有其他方式,我不必在父组件中浅拷贝?我想知道'kendo-grid'如果没有明确的浅拷贝就没有它。 – cyberpirate92

+0

@ cyberpirate92我对kendo-grid并不熟悉,但它可能不依赖于ngOnChanges钩子。 (https://plnkr.co/edit/G1dlSJqtcJ9NX7F44zaz?p=preview)在这个plunkr中,你可以看到子组件在ngFor中确实发生了变化。但就你而言,由于你的ngOnChanges钩子中有'extractRowsAndColumns'方法,所以你需要运行它。 – LLai

0

为一个简单的解决你的问题,你可以检测@Input变化ngOnChanges这样的:

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

希望它能帮助: )

+0

我已经实现了'OnChanges',但它不工作。 – cyberpirate92

+0

你想要什么:如果'data'的值改变了,你用新的'data'调用方法'extractRowsAndColumns'来更新组件,对吗? –

+0

是的,这正是我想要的 – cyberpirate92

1

只要让你@Input()双向绑定...

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

我以前也有同样的问题; ngOnChanges方法仅侦听数据类型==!数组上的更改。

解释(ngOnChanges not firing for nested object):

在变化检测,当角检查组件的输入 属性变化时,它使用(基本上)===为脏检查。 对于数组,这意味着只检查数组引用(仅)。 由于rawLapsData数组引用不变,因此不会调用ngOnChanges() 。

+0

你是对的,孩子的数据确实得到了更新,但是'ngOnChanges'事件没有被解雇。我尝试使用'setInterval'记录子组件中的数据,并且我可以看到它正在更新。 – cyberpirate92