2017-10-19 2 views
0

Ich versuche, eine eckige Komponente zu erstellen, die eine HTML-Tabelle mit dem bereitgestellten Objekt-Array rendert.Angular: Wie @Input Änderungen abonnieren

Ich habe OnChanges implementiert, um Änderungen an der @Input zu erkennen, scheint es aber nicht zu funktionieren.

Zum Testen verwende ich setInterval, um einige Daten hinzuzufügen, aber es wird nicht in der untergeordneten Komponente wiedergegeben.

Dieses es den Code, den ich bisher habe,

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> 

Ich verwende die obige Komponente in 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> 

Wie kann ich das Komponenten-Update, wenn @Input Änderungen vornehmen?

UPDATE: ich eine plunkr erstellt haben demonstriert dies: https://plnkr.co/edit/szz1SNooQ1vIZhnFgiys?p=preview

+0

versuchen einen beobachtbaren Eingangs geändert hat dies unter Bezugnahme [* * antwort **] (https://stackoverflow.com/questions/44467336/observable-of-input-property/44467942#44467942) – Aravind

+0

Wer daran interessiert ist, kann sich hier den vollständigen Code ansehen: https: // github .com/cyberpirate92/ngTable – cyberpirate92

Antwort

1

Wie TimHovius sagte, macht eckig nur eine Referenzprüfung. Da Sie auf das gleiche Array drücken, erkennt die ng-table.component keine Änderung (die Referenz auf die Eingabe ist immer noch dieselbe). Eine Sache, die Sie tun können, ist, eine flache Kopie des Arrays zu erstellen.

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

Jetzt ng-table.component erkennt, dass der Eingang und der Feuer ngOnChanges

hier ein plunkr ist Demonstrieren diese (https://plnkr.co/edit/2tdMEA9PLc2TEL4Gy4Lp?p=preview)

+0

@ cyberpirate92 vergessen, meine PLNKR hinzufügen – LLai

+0

Dank @LLai, seichtes Kopieren funktioniert. Ich habe mich gefragt, ob es noch einen anderen Weg gibt, wo ich keine flache Kopie in der Elternkomponente haben muss? Ich frage mich, wie 'Kendo-Grid' es ohne eine explizite flache Kopie macht. – cyberpirate92

+0

@ cyberpirate92 Ich bin nicht vertraut mit Kendo-Grid, aber es ist wahrscheinlich nicht auf den ngOnChanges-Hook angewiesen. (https://plnkr.co/edit/G1dlSJqtcJ9NX7F44zaz?p=preview) In diesem Plunkr können Sie sehen, dass die untergeordnete Komponente Änderungen in ngFor aufnimmt. Aber in Ihrem Fall, da Sie die Methode 'extractRowsAndColumns' in Ihrem ngOnChanges-Hook haben, benötigen Sie diese zur Ausführung. – LLai

0

als eine einfache Lösung für Ihr Problem, können Sie @Input Änderungen in ngOnChanges wie dies erkennen:

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

Hoffe, es hilft:)

+0

Ich habe 'OnChanges' implementiert, aber es funktioniert nicht. – cyberpirate92

+0

was willst du: wenn 'data's Wert geändert wird, aktualisierst du die Komponente, indem du die Methode' extractRowsAndColumns' mit den neuen 'data' aufrufst, habe ich recht? –

+0

Ja das ist genau das, was ich will – cyberpirate92

1

Machen Sie einfach Ihre @Input() Zwei-Wege-Bindung ...

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

Ich hatte das gleiche Problem vorher; Die ngOnChanges Methode hört nur auf Änderungen an Datentypen ==! Array.

Erklärung (ngOnChanges not firing for nested object):

Während Änderungserkennung, wenn Angular Prüfungen Komponenten -Eingang Eigenschaften für den Wandel, verwendet es (im Wesentlichen) === für schmutzige Prüfung. Für Arrays bedeutet dies, dass die Array-Referenzen (nur) dreckig überprüft werden. Da sich die RawLapsData-Array-Referenz nicht ändert, wird ngOnChanges() nicht aufgerufen.

+0

Sie haben Recht, die Daten im Kind werden zwar aktualisiert, aber das 'ngOnChanges' Ereignis wird nicht ausgelöst. Ich habe versucht, die Daten in der Kindkomponente mit 'setInterval' zu protokollieren und ich konnte sehen, dass es aktualisiert wird. – cyberpirate92

Verwandte Themen