3

I have 20 columns in the grid. I want the grid to be split in half, where in the left half I can scroll through the first 10 columns, and in the right half I can scroll through the last 10 columns. In other words, I want there to be two horizontal scrolls in the same Grid. Is it possible?

Marc Iskander
  • 157
  • 11
  • Why not create two different grids with each having 10 columns? – isAif Jan 18 '21 at 10:36
  • Because I have other functionalities that I wouldn't prefer to do manually, like row dragging and row expand/collapse – Marc Iskander Jan 18 '21 at 11:30
  • i didn't try this so i honestly don't know if it works and serves your purpose but, here is the documentation of Aligned grids, where you get two synchronized grids : https://www.ag-grid.com/documentation/javascript/aligned-grids/ it doesn't say if it supports row dragging from one grid to another, you may need to implement that yourself. – Kaki Master Of Time Jan 19 '21 at 10:21
  • 1
    what you're trying to do isn't natively possible in ag-Grid. See [here](https://plnkr.co/edit/FB9lQ3HGkwriOJYR) for a VERY hacky solution. – ViqMontana Jan 19 '21 at 17:34
  • Thanks @ViqMontana. Will try to figure out how to maintain styles and show scrollbar for the pinned columns. – Marc Iskander Jan 20 '21 at 15:15

3 Answers3

3

The functionality you're trying to implement doesn't natively exist in ag-Grid. One solution would be to use pinned columns where you pin 10 columns to the left. The problem would be that you cannot scroll pinned columns, therefore you'll have the add some extra css in order to modify the grid to your needs.

NB. this is VERY hacky solution:

Add the following to your css in order for the pinned columns to be scrollable (change the width from 200px do your desired width):

.ag-pinned-left-cols-container {
  min-width: 200px !important;
  width: 200px !important;
  overflow: auto !important;
}

.ag-horizontal-left-spacer {
  width: 200px !important;
  max-width: 200px !important;
  min-width: 200px !important;
}

.ag-pinned-left-header{
  width: 200px !important;
  max-width: 200px !important;
  min-width: 200px !important;
  overflow: hidden !important;
}

You'll also need to make sure the pinned column headers scroll along with the pinned columns. For this, you can use an event listener:

document.getElementsByClassName('ag-pinned-left-cols-container')[0].addEventListener("scroll", this.runOnScroll, {passive: true});

runOnScroll =  function(evt) {
  document.getElementsByClassName('ag-pinned-left-header')[0].scrollTo(evt.srcElement.scrollLeft, 0)

Demo.

ViqMontana
  • 5,090
  • 3
  • 19
  • 54
  • What about the columns reordering? It stops working if we use the code above. – manymanymore Jul 05 '22 at 13:08
  • @manymanymore that's why I said it's a very hacky solution – ViqMontana Jul 05 '22 at 15:09
  • Hi, @ViqMontana, I used your example code for angular but the issue I am facing is that the header moves back to the initial position after stopping the scroller. Any idea why it is happening for the angular? – Abdul Moeez Jan 22 '23 at 19:35
  • in the demo and in my implementation of this fix the pinned left scroll bar doesn't have the bar in it to scroll left and right. I can confirm everything else about this works if you add a scroller to the column header section and flip the event listener. but really need the scroll bar to work in the proper place at the bottom. also the columns that are hidden in the pinned section when you scroll across to them all the row line breaks are missing is there anything can be done to make these redraw correctly when it scrolls. Demo v 2 https://plnkr.co/edit/GMqgvQjRsC5Tqf0C?preview – Aurelius May 15 '23 at 10:42
0

For those interested in ViqMontana's solution: In version 28.1.1 they added a new event-listener which resets any scroll inside the header (commit 12552505). It says this would fix bug "AG-7137", which I can't find out what it was.

It's possible to remove this listener after the grid is ready:

const api = this.gridOptions.api;
api?.ctrlsService.leftHeaderRowContainerCtrl.destroyFunctions[6]?.();
api?.ctrlsService.rightHeaderRowContainerCtrl.destroyFunctions[6]?.();

After this the header scrolls correctly. When using TypeScript, you will need to cast api to any.

tdy
  • 36,675
  • 19
  • 86
  • 83
0

Hi I managed to get this in a pretty good working state with help from ViqMontana's comment

Demo

The first thing to note is that because of how hacky this solution is it can break existing ag grid core functionality and will only really work with aggrid paging enabled

pagination={true}
paginationAutoPageSize={true}

we need to wrap each section inside the grid in our own containers

    //wrap the pinned left header area
    var headerParent = document.getElementsByClassName('ag-header')[0];
    var headerChild = document.getElementsByClassName('ag-pinned-left-header')[0];
    var newHeaderContainer = document.createElement('div');
    newHeaderContainer.id = 'header-container';
    newHeaderContainer.className = 'header-container';
    // set the newDivContainer as child (instead of the element)
    headerParent.replaceChild(newHeaderContainer, headerChild);
    // set element as child of newDivContainer
    newHeaderContainer.appendChild(headerChild);


    //wrap the pinned left Data area
    var dataParent = document.getElementsByClassName('ag-body-viewport')[0];
    var dataChild = document.getElementsByClassName('ag-pinned-left-cols-container')[0];
    var newDataContainer = document.createElement('div');
    newDataContainer.id = 'data-container';
    newDataContainer.className = 'data-container';
    // set the newDivContainer as child (instead of the element)
    dataParent.replaceChild(newDataContainer, dataChild);
    // set element as child of newDivContainer
    newDataContainer.appendChild(dataChild);   


    //wrap the non pinned data area
    var unpinnedDataParent = document.getElementsByClassName('ag-center-cols-viewport')[0];
    var unpinnedDataChild = document.getElementsByClassName('ag-center-cols-container')[0];
    var newUnpinnedDataContainer = document.createElement('div');
    newUnpinnedDataContainer.id = 'unpinned-data-container';
    newUnpinnedDataContainer.className = 'unpinned-data-container';
    // set the newDivContainer as child (instead of the element)
    unpinnedDataParent.replaceChild(newUnpinnedDataContainer, unpinnedDataChild);
    // set element as child of newDivContainer
    newUnpinnedDataContainer.appendChild(unpinnedDataChild);


    //wrap the non pinned header area
    var unpinnedHeaderParent = document.getElementsByClassName('ag-header-viewport')[0];
    var unpinnedHeaderChild = document.getElementsByClassName('ag-header-container')[0];
    var newUnpinnedHeaderContainer = document.createElement('div');
    newUnpinnedHeaderContainer.id = 'unpinned-header-container';
    newUnpinnedHeaderContainer.className = 'unpinned-header-container';
    // set the newDivContainer as child (instead of the element)
    unpinnedHeaderParent.replaceChild(newUnpinnedHeaderContainer, unpinnedHeaderChild);
    // set element as child of newDivContainer
    newUnpinnedHeaderContainer.appendChild(unpinnedHeaderChild);

because these are separate entities that can scroll individually connect them with event listeners to scroll at the same time

document.getElementsByClassName('data-container')[0].addEventListener("scroll", this.runOnScroll1, { passive: true });
document.getElementsByClassName('unpinned-data-container')[0].addEventListener("scroll", this.runOnScroll2, { passive: true });

and their corresponding functions they call

runOnScroll1=  function(evt) {
document.getElementsByClassName('header-container')[0].scrollTo(evt.srcElement.scrollLeft, 0)};
runOnScroll2=  function(evt) {
document.getElementsByClassName('unpinned-header-container')[0].scrollTo(evt.srcElement.scrollLeft, 0)};

Finally you need to set and override a bunch of css styles to our new containers and some of the grids classes

    .ag-body-viewport{
        overflow: hidden !important;
    }
    .ag-header {
        height: 55px !important;
    }
    .data-container {
        min-width: 50% !important;
        max-width: 50% !important;
        width: 50% !important;
        height: 100% !important;
        overflow-x: scroll !important;
        overflow-y: hidden !important;
    }
    .unpinned-data-container {
        height: 100% !important;
        overflow-y: hidden !important;
        overflow-x: scroll !important;
    }
    .ag-horizontal-left-spacer {
        visibility: hidden;
    }
    .header-container {
        height: 120px !important;
        width: 50% !important;
        max-width: 50% !important;
        min-width: 50% !important;
        overflow-x: hidden !important;
        overflow-y: hidden !important;
    }
    
    .unpinned-header-container {
        height: 120px !important;
        overflow-y: hidden !important;
        overflow-x: hidden !important;
    }
Aurelius
  • 178
  • 1
  • 1
  • 14