ngx-datatable icon indicating copy to clipboard operation
ngx-datatable copied to clipboard

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

Open arlowhite opened this issue 7 years ago • 9 comments

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

  • Table version: 9.1.0
  • Angular version: 4.0.2
  • Browser: all

  • Language: all

arlowhite avatar May 15 '17 17:05 arlowhite

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.

arlowhite avatar May 15 '17 17:05 arlowhite

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

amcdnl avatar May 17 '17 12:05 amcdnl

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

MorlaRamakrishna avatar May 24 '17 05:05 MorlaRamakrishna

@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

bheda91 avatar Jun 20 '17 07:06 bheda91

@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 avatar Jun 20 '17 17:06 arlowhite

@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.

arlowhite avatar Jun 20 '17 17:06 arlowhite

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.

thatcort avatar Sep 11 '18 14:09 thatcort

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.

pratap95 avatar Jun 16 '23 09:06 pratap95

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.