Bertijn Pauwels
Bertijn Pauwels

Reputation: 585

Angular6: Input binding on custom component doesn't update correctly

First question ever on StackOverflow, how exciting!

Currently I have two custom components, both accepting a couple of input variables :

<sod-matrix-table #matrix 
  [entities]="entities" 
  [pairs]="pairs" 
  [displayedColumns]="displayedColumns">
</sod-matrix-table>

and :

<data-table 
  #table 
  [type]="sodMatrixQuery.targetType" 
  [query]="sodMatrixQuery" >
</data-table>

When updating the entities, pairs or columns of the first tag, everything updates correctly. For example, when I update the displayedColumns array in a component that uses the matrix table tag, the table inside of that component gets updated with the desired columns.
However, when I update the sodMatrixQuery in the component, and press the search button, the query object of the data-table isn't updated correctly, although they are bound together.

Example:

data-table has a field query and uses this query to send REST requests to the server. SODMatrixComponent has a field sodMatrixQuery and uses the tag of the data-table, binding his field to the other field.

An SOD Matrix contains pairs of objects. When I select 2 pairs, and press the search button, the data-table sends the REST request with 2 pairs. However, when I remove the two pairs, and press search again, the data-table component sends another REST request, again with 2 pairs instead of none. When pressing the search button a second time, the correct request is send.

I debugged and internally everything with the pairs goes fine, it's only the databinding that doesn't get updated in time. Any thoughts about this?

EDIT: This is the code that happens on the button click:

public search() {
    const tempQuery = new SODMatrixQuery(this.lhsType, this.rhsType, [], this.entities);

    // Only look at elements above the diagonal
    for (let i = 1; i < this.pairs.length; i++) {
        for (let j = 0; j < i; j++ ) {
            const p = this.pairs[i][j];
            if (p.checked) {
                tempQuery.addToxicPair(p);
            }
        }
    }

    if (this.dataTable) {
        this.sodMatrixQuery = tempQuery;
        // this.dataTable.query = tempQuery;
        this.dataTable.loadDataPage();
    }

}

SODMatrixComponent variables :

@ViewChild("table")
public dataTable: ElimityDataTableComponent;

public sodMatrixQuery: SODMatrixQuery;

Datatable component :

@Input()
public query: Query;

SODMatrixQuery extends Query!

The commented line below is a fix, to update the query object directly, but I'm just curious why the databinding doesn't work.

Upvotes: 3

Views: 231

Answers (1)

Maximilian Riegler
Maximilian Riegler

Reputation: 23506

Looks like change detection would need a moment to breathe there - the databinding can't be updated between the setting of the sodMatrixQuery member and the this.dataTable.loadDataPage() call - that's why it still has the old value on the first call. After that change detection will be run and on the second call it will have the right values.

if (this.dataTable) {
    this.sodMatrixQuery = tempQuery;
    // can't update the bindings here
    this.dataTable.loadDataPage();
}

So looking at your current architecture, it would be better to move the loadDataPage() call to the dataTable component into the OnChanges lifecycle hook, like Agash said in the comments.

export class ElimityDataTableComponent implements OnChanges {
  // ...
  ngOnChanges(changes: SimpleChanges) {
    if (changes.query) {
      this.loadDataPage();
    }
  }

This way, every time you update the sodMatrixQuery, it automatically loads the new data.

Upvotes: 2

Related Questions