1

I have been going round in circles trying to apply ngx-perfect-scrollbar to ag-grid. I can get both working separately, but I want to completely replace the default scrollbar on my datatable with perfect-scrollbar.

I have set up my module as per their instructions:

import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
import { PerfectScrollbarConfigInterface } from 'ngx-perfect-scrollbar';

const PERFECT_SCROLLBAR_CONFIG: PerfectScrollbarConfigInterface = {
  suppressScrollX: true
};

@NgModule({
  declarations: [

  ],
  imports: [
    PerfectScrollbarModule.forRoot(PERFECT_SCROLLBAR_CONFIG)
  ]
})

and in my template:

<perfect-scrollbar class="psc">
    <ag-grid-angular #agGrid style="width:100%;height:100%" class="ag-dark"
                     [gridOptions]="gridOptions"
                     [rowData]="rowData">
    </ag-grid-angular>
</perfect-scrollbar>

This simply results in the outer element appearing with the new custom scrollbar, containing the datagrid with the standard toolbar. I need to apply both directives to the same element I guess, but I'm lost as to how to do this.

I was also trying this approach, using the standard (non-angular) perfect-scrollbar package, and trying to bind it to the correct .ag-body-viewport element when the component is loaded:

import perfectScrollbar from 'perfectScrollbar';

this.viewport = this.$element.find('.ag-body-viewport')[0];
perfectScrollbar.initialize(this.viewport);

but I can't get it to work either; I just get the "no default export" error...

Any pointers appreciated. Thanks

Inigo
  • 8,110
  • 18
  • 62
  • 110

4 Answers4

3

Steps To Add perfect scroll Bar in ag-grid-angular to your Angular 7 application (Horizontally + Vertically).


  1. Add perfect-scrollbar library from this link to you package.json file
  2. Import library in ag-grid-angular used component
    import PerfectScrollbar from 'perfect-scrollbar';
  3. Add style to your angular.json file with perfect-scrollbar.css
  4. Add this css to your style.css file

    .ag-body-viewport, .ag-body-horizontal-scroll-viewport{ position: relative; overflow: hidden !important; }

  5. Add template reference variable to you HTML and pass to the grid-ready event
    <div class="table-responsive" #gridContainer> <ag-grid-angular (gridReady)="onGridReady($event,gridContainer)"> </ag-grid-angular> </div>

  6. In Component add this method as below to initialize scroll

    onGridReady(params: any,gridContainer) { let array=[ ".ag-body-viewport"," .ag-body-horizontal-scroll-viewport"] array.forEach(element => { let container = <HTMLElement> gridContainer.querySelector(element) if(container){ const ps = new PerfectScrollbar(container); ps.update(); } }); }

Surendranath Sonawane
  • 1,595
  • 1
  • 18
  • 24
  • This one worked perfect, one update from my side is if we use @ViewChild element reference, Instead of using `let container = gridContainer.querySelector(element)` We must use `let container = gridContainer.nativeElement.querySelector(element)` – Sajeer Babu Feb 09 '21 at 06:07
  • for me this works fine vertically, but Horizontally it scrolls one time only! then it stays frozen even if I move the scrollbar... – Chris Mar 23 '21 at 10:29
1

I implemented it in ag-grid-angular:

  1. import PerfectScrollbar from 'perfect-scrollbar'; (so I am not using ngx-perfect-scrollbar just base perfect-scrollbar package);
  2. you can do it later like you need but for tests copy styles from perfect-scrollbar to your component which keeps ag-grid-angular and also for tests: switch to viewEncapsulation.None.
  3. I am running it in ngAfterViewInit lifehook of component which keep ag-grid-angular. But probably it can be also onAgGridReady event . The method which I am calling in ngAfterViewInit looks like this:

    private runPerfectScrollbar() {
    const agBodyViewport = window.document.getElementsByClassName('ag-body-viewport')[0];
    this.perfectScrollbar = new PerfectScrollbar(agBodyViewport);
    this.perfectScrollbar.update();
    

    }

  4. you need to care about some cases then. For example when column resizing I am running this.perfectScrollbar.destroy() on (dragStarted) event of ag-grid. and I am calling again this runPerfectScrollbar() again when (dragStopped).

  5. If you see problems with performance for example on firefox set suppressColumnVirtualisation: window.navigator.userAgent.toLowerCase().indexOf('firefox') > -1 ? true : false. (of course write it better in some method ;))

    But I was suprised that for me it solved some other issues. For example I don't have more lag on firefox on scroll. On safari I don't have rubber band effect on overscroll.

I am not sure also about all settings in ag grid. I have paging on my view. So I have limited rows to display. But if you have some problems, I will try to help.

1

I figured out another way of achieving this with:

  • Angular 8.0.0
  • ag-grid 17.1.0
  • ngx-perfect-scrollbar 7.2.1

app.module.ts

Imports the PerfectScrollbarModule in the corresponding module

@NgModule({
    imports: [
        PerfectScrollbarModule,
    ],
})
export class AppModule {}

styles.scss

/* Hides the scrollbars in the ag-grid table */
.ag-theme-bootstrap .ag-body-viewport,
.ag-theme-bootstrap .ag-body-viewport .ag-body-horizontal-scroll-viewport,
.ag-theme-bootstrap .ag-body-viewport .ag-body-vertical-scroll-viewport {
    position: relative;
    overflow: hidden !important;
}

app.component.html

For the sake of simplicity I just left the bindings of the ag-grid to be added to make this thing work.

The key here is:

  • Usage of the PerfectScrollbarDirective instead of the
  • Assign the width of the ag-grid to the scroll width of its viewport
  • Hide the horizontal scrollbars
  • Make this every time that a column is resized in the table

The goal is to be able to invoke the update method of the PerfectScrollbarDirective in order to reflect the changes on the UI after the new width is set upon column resizing:

<div class="table-container ps" [perfectScrollbar]="config">
    <ag-grid-angular
        style="width: 100%"
        [style.width.px]="width"
        [suppressHorizontalScroll]="true"
        (columnResized)="onColumnResized()"
    >
    </ag-grid-angular>
</div>

app.component.scss

This is always needed by the ngx-perfect-scrollbar:

.table-container {
    position: relative;
    max-height: your height here;
}

app.component.ts

The update method of the PerfectScrollbarDirective is called in order to reflect the changes on the UI. Otherwise the new width is set on the ag-grid component, but the perfect-scrollbar does not reflect the change.

export class TableComponent {
    public width: number = null; // This must be null otherwise it does not work properly after calling the sizeColumnsToFit function

    @ViewChild(PerfectScrollbarDirective, { static: false })
    public directiveRef?: PerfectScrollbarDirective;

    public config: PerfectScrollbarConfigInterface = {};

    public constructor(private store: Store<AppState>, private elementRef: ElementRef) {}

    public onColumnResized(): void {
        this.updateTableWidth();
    }

    private updateTableWidth(): void {
        const agBodyViewport: HTMLElement = this.elementRef.nativeElement.querySelector(".ag-body-viewport");
        if (agBodyViewport) {
            if (agBodyViewport) {
                this.width = agBodyViewport.scrollWidth > agBodyViewport.offsetWidth ? agBodyViewport.scrollWidth : null;
                this.directiveRef.update();
            }
        }
    }
}
Salcedonia
  • 11
  • 2
0

Try to import the perfect scrollbar like this:

import * as perfectScrollbar from 'perfect-scrollbar';

then you can go with perfectScrollbar.initialize() and perfectScrollbar.update();

mkolev
  • 53
  • 1
  • 4