2017-10-19 28 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