swimlane / ngx-datatable

✨ A feature-rich yet lightweight data-table crafted for Angular
http://swimlane.github.io/ngx-datatable/
MIT License
4.63k stars 1.68k forks source link

Duplicated column-object after resize #987

Open gen4sp opened 7 years ago

gen4sp commented 7 years ago

I'm submitting a ... (check one with "x")

[x] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, post on Stackoverflow or Gitter

Current behavior

After resize, column-object in a template is different, then it was before. For example, before resizing, I can increase some value column.test and it will be displayed correctly. After resizing it freezing, like column object was cloned.

Expected behavior

column-object should be the same after resize

Reproduction of the problem

http://plnkr.co/edit/GSJZ2hYRSQJR80milgZU run it, resize any column

What is the motivation / use case for changing the behavior?

Unexpected behaviour, sometimes it essential to control data for entire column

Please tell us about your environment:

not important

wizarrc commented 7 years ago

@gen4sp columns are being cloned every resize, look here: https://github.com/swimlane/ngx-datatable/blob/master/src/components/datatable.component.ts#L886

/**

   * The header triggered a column resize event.

   */
  onColumnResize({ column, newValue }: any): void {
    /* Safari/iOS 10.2 workaround */
    if (column === undefined) {
      return;
    }

    let idx: number;
    const cols = this._internalColumns.map((c, i) => {
      c = { ...c };

      if (c.$$id === column.$$id) {
        idx = i;
        c.width = newValue;

        // set this so we can force the column
        // width distribution to be to this value
        c.$$oldWidth = newValue;
      }

      return c;
    });

    this.recalculateColumns(cols, idx);
    this._internalColumns = cols;

    this.resize.emit({
      column,
      newValue
    });
  }

Also note that the resize event gives you the column that was resized. Until this behavior is changed, you can subscribed to the event and update the column that you provided the table.

wizarrc commented 7 years ago

I want to point out that this is only a concern when the cell template uses user supplied data in the column.

@amcdnl consider making the columns collection a map in lieu of cloning objects that stores the context such as oldWidth and/or width so that cell templates that get it's data from user supplied values in the column will be up-to-date.

@gen4sp You can workaround the issue by making a sub-property like so:

<ng-template #customTmpl let-row="row" let-value="value" let-i="index"  let-col="column" >
          +{{value}}[{{col.test.val}}]
        </ng-template>
...
setInterval(()=>{
        this.cols[1].test.val++;
      }, 100);
...
  ngOnInit() {
    console.log('A')
    // Add property `test: {val: 0}` instead of `test: 0`
    this.cols = [{name:"Name"},{name:"Gender", test:{val: 0}, cellTemplate:this.customTmpl},{name:"Company"}]
  }
...

http://plnkr.co/edit/DC3PzLP5ZnoO8oLx0h5l?p=info

gen4sp commented 7 years ago

@wizarrc Thank you for a quick response and nice workaround idea!