How to synchronise the scroll position of two different kendo-grids

2 Answers 675 Views
Grid
Murray
Top achievements
Rank 1
Iron
Veteran
Murray asked on 09 Jun 2022, 03:12 PM

I have multiple grids in a view and when the user drags on the scrollbar of one grid I want it to automatically scroll the other grids exactly the same amount up or down.

 

So in my ngAfterViewInit() method I have the following:

document.querySelector(".k-grid .k-grid-content").addEventListener("scroll", (e) => {

console.log('scroll event', e);

}

The idea is that I can then capture this event and pass it to the other grids so they can scroll too. However this isn't working as the event listener doesn't fire. Can you suggest a way to make this work?

 

 

2 Answers, 1 is accepted

Sort by
0
Accepted
Christopher
Top achievements
Rank 1
Iron
answered on 09 Jun 2022, 08:53 PM

I've gotten this working for syncing both scrolling and row hovering. In my implementation, your grid component ("app-my-data-grid") should implement IElementRef:

@Component({
    selector: 'app-my-data-grid',
    template: `<kendo-grid ...></kendo-grid>`,
    changeDetection: ChangeDetectionStrategy.OnPush,
    encapsulation: ViewEncapsulation.None,
    styles: [`
        app-my-data-grid .hide-scrollbar > * {
            margin-right: -7px;
        }
    `]
})
export class MyDataGridComponent implements AfterViewInit, IElementRef {
    @Input() data: any[];
    @Input() hideScrollbar: boolean = true;
    @Output() contentScroll: EventEmitter<ContentScrollEvent>; //The event we'll listen to
    @ViewChild(GridComponent, { static: true }) gridEl: GridComponent; //Our actual kendo grid reference
    public element: Element; //Part of IElementRef, so the sync functions have something to reference

    constructor(elRef: ElementRef) {
        this.element = elRef.nativeElement;
    }

    ngAfterViewInit(): void {
        this.contentScroll = this.gridEl.contentScroll; //use the kendo grid's native scroll event
    }
// your logic ...
}
Then encompassing that is a directive that wraps all the grids that should be synced.
<app-grid-sync [gridDataChanged]="dataChange$ | async">
    <app-my-data-grid
        *ngFor="let gridDataSet of dataSet; last as isLast"
        [data]="gridDataSet"
        [hideScrollbar]="!isLast">
    </app-my-data-grid>
</app-grid-sync>

This will assigns the array of grids to a scroll sync set and a hover sync set. These "sets" manage the events from the element the user is scrolling/hovering on and syncs that to the others.

The actual event listeners are in ScrollSet and HoverSet. The factories aren't that helpful. They really just provide ngZone. As for the names of the events being listened to, those are in the grid-sync directive near the bottom:

private setScrollSync(grids) {
    this.clearScrollSync();
    if (!grids?.length) {
        return;
    }
    this.elementSubs = this._scrollSyncFactory.syncVerticalScroll(grids, "contentScroll", "k-grid-content");
}

private setHoverSync(grids) {
    this.clearHoverSync();
    if (!grids?.length) {
        return;
    }
    setTimeout(() => { //If I remember correctly, this allows the tr elements time to be created. Might be better to use a MutationObserver
        this.hoverSubs = this._hoverSyncFactory.syncHover(grids, ".k-grid-content tr", ["k-state-hover", "hover"]);
    }, 0);
}
Let me know if you have any issues getting this running in your project. Files are attached with the full implementations.
Murray
Top achievements
Rank 1
Iron
Veteran
commented on 10 Jun 2022, 12:17 PM

Hi Christopher, thanks for the detailed code walkthrough and samples. I am very pleased to say I have successfully integrated this code and have scroll syncing working. It's certainly a non-trivial solution which I doubt I would have been able to develop myself.
0
Vinicius
Top achievements
Rank 1
Iron
answered on 13 Mar 2023, 03:50 PM

Hey @Christopher, I've been working a week trying to do that and now I find your implementation, and from @Murray's feedback its look like working!

Can you help me a bit with that, I saw the files and try to implement them, but maybe I'm missing something here.

I added the files and interface, and imported everything, it is building but I'm not able to find why it's not working, maybe missing the difference between the grid-component and usage-component files you posted.

 

Appreciate any help!

 

Christopher
Top achievements
Rank 1
Iron
commented on 13 Mar 2023, 04:10 PM

In your .ts file, do you have both templateUrl and template defined on purpose (lines 33 and 36)? You'll need to separate the grid portion into its own component. Something like ReleaselinePricingDetailsGridComponent. Then reference those new grid components with the *ngFor
Tags
Grid
Asked by
Murray
Top achievements
Rank 1
Iron
Veteran
Answers by
Christopher
Top achievements
Rank 1
Iron
Vinicius
Top achievements
Rank 1
Iron
Share this question
or