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.67k forks source link

Horizontal scroll not resumed after filter all rows, then unfilter. #756

Open arlowhite opened 7 years ago

arlowhite 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
[x] feature request
[ ] support request => Please do not submit support request here, post on Stackoverflow or Gitter

Current behavior

Using the Horizontal scrolling demo, add buttons to show empty rows and then resume original rows. (I'll post code in a comment) http://localhost:9999/#horz-vert-scrolling

  1. Horizontal scroll to right
  2. Click Empty Rows
  3. Click Show Rows

Columns will still be scrolled to right, but body scroll will be reset to beginning.

Expected behavior

Either: A. Column and Body scroll should be reset to 0 B. Column and Body scroll should resume the last horizontal scrolled position before 0 rows displayed.

Reproduction of the problem

import { Component } from '@angular/core';

@Component({
  selector: 'horz-vert-scrolling-demo',
  template: `
    <div>
      <h3>
        Horizontal and Vertical Scrolling
        <small>
          <a href="https://github.com/swimlane/ngx-datatable/blob/master/demo/basic/scrolling.component.ts" target="_blank">
            Source
          </a>
        </small>
      </h3>
      <div>
        <button (click)="showEmptyRows()">Empty Rows</button>
        <button (click)="showOriginalRows()">Show Rows</button>
      </div>
      <ngx-datatable
        class="material"
        [rows]="rows"
        columnMode="force"
        [headerHeight]="50"
        [footerHeight]="0"
        [rowHeight]="50"
        [scrollbarV]="true"
        [scrollbarH]="true">
        <ngx-datatable-column name="Name" [width]="300"></ngx-datatable-column>
        <ngx-datatable-column name="Gender"></ngx-datatable-column>
        <ngx-datatable-column name="Age"></ngx-datatable-column>
        <ngx-datatable-column name="City" [width]="300" prop="address.city"></ngx-datatable-column>
        <ngx-datatable-column name="State" [width]="300" prop="address.state"></ngx-datatable-column>
      </ngx-datatable>
    </div>
  `
})
export class HorzVertScrolling {

  rows = [];

  originalRows: any[];

  constructor() {
    this.fetch((data) => {
      this.rows = data;
      this.originalRows = data;
    });
  }

  fetch(cb) {
    const req = new XMLHttpRequest();
    req.open('GET', `assets/data/100k.json`);

    req.onload = () => {
      cb(JSON.parse(req.response));
    };

    req.send();
  }

  showEmptyRows() {
    this.rows = [];
  }

  showOriginalRows() {
    this.rows = this.originalRows;
  }

}

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

Many users of ngx-datatable probably have large horizontally scrolled tables that have filter UI. Users often briefly display empty rows as they adjust their table filters and will encounter this bug.

Please tell us about your environment:

Reproduced in ngx-datatable#master demo 42364cc91b29003bde1a146d23e6fa855a5a0176

arlowhite commented 7 years ago

To reset scroll at 0, recalculateColumns() needs to be called after going from empty rows to displayed rows.

However, my vote is for resuming the scrolled position. I already implemented this in my project.

Capture scroll events (scroll)="onTableScroll($event)"

Store last offsetX

  onTableScroll(scroll: any) {
    const offsetX = scroll.offsetX;
    // can be undefined sometimes
    if (offsetX != null) {
      this.offsetX = offsetX;
    }
  }

After rows are updated, resume the offsetX

    setTimeout(() => {
      this.scrollX(this.offsetX);
    }, 1);

  scrollX(offsetX: number) {
    this.datatableBodyElement.scrollLeft = offsetX;
  }

Let me know if you want me to work on creating a PR or not.

amcdnl commented 7 years ago

I fancy resetting it to 0. I thought we were doing this...

MorlaRamakrishna commented 7 years ago

I am using 6.3.0 version If we added both rowHeight=auto and scrollbars =true { i.e [scrollbarV]="true" [scrollbarH]="true"} getting error like Row Height cache initialization failed. Please ensure that 'rowHeight' is a valid number value: (auto) when 'scrollbarV' is enabled.

if we mention row height with numeric value some rows are missing

bheda91 commented 7 years ago

@arlowhite @amcdnl The given solution is not working.

Can you please suggest any other solution?

Table version: 9.0.0

Angular version: 4.1.0

Browser: all

Language: all

arlowhite commented 7 years ago

@MorlaRamakrishna Sounds like a different issue; you should upgrade to the latest ngx-datatable version first and see if you still have the problem.

arlowhite commented 7 years ago

@bheda91 All I know, is that for me, calling recalculateColumns() fixed the header horizontal scroll being offset from the table body horizontal scroll. But you may have to call it within a timeout. You could also try triggering ChangeDetection if that doesn't work.

However, in my case, I wanted the horizontal scroll to resume where it was instead of at 0, so that's the reason for the scrollLeft code.

thatcort commented 6 years ago

The workaround here didn't work for me. I'm using ngx-datatable version 11.3.2 (using Angular 5) and the closest I came to it working is calling this.datatable._offsetX.next(offsetX), but I have a pinned left column that gets laid out wrong when I do this. I realize this is an old ticket, but any suggestions are welcome.

pratap95 commented 1 year ago

To reset scroll at 0, recalculateColumns() needs to be called after going from empty rows to displayed rows.

However, my vote is for resuming the scrolled position. I already implemented this in my project.

Capture scroll events (scroll)="onTableScroll($event)"

Store last offsetX

  onTableScroll(scroll: any) {
    const offsetX = scroll.offsetX;
    // can be undefined sometimes
    if (offsetX != null) {
      this.offsetX = offsetX;
    }
  }

After rows are updated, resume the offsetX

    setTimeout(() => {
      this.scrollX(this.offsetX);
    }, 1);

  scrollX(offsetX: number) {
    this.datatableBodyElement.scrollLeft = offsetX;
  }

Let me know if you want me to work on creating a PR or not.

Hi @arlowhite , I am getting error in datatableBodyElement ... Can you please send the link where you have already implemented this feature.

jim-lautaro-cargoproduce commented 1 year ago

My custom fix:

@ViewChild('ngxDatatableRef') ngxDatatableRef: NgxDatatableComponent;

this.ngxDatatableRef.headerComponent._offsetX = 0;
this.ngxDatatableRef.columnTemplates.setDirty();
this.ngxDatatableRef.recalculate();

It's ugly but I'm posting it in case it helps someone else.