18

Using Ag-Grid, users can drag columns to order them the way they like. I need to allow the user to save their column order (to an SQL backend) so that it becomes the default column order for them. I was trying to get the column names like this:

var cols = schedGridOptions.columnApi.getAllColumns();
for (col in cols) {
    var colDef = col.getColDef();
    console.log(colDef.headerName);
}

This was an example I found for setting the header name, so I tried to adapt it to getting the header name. But I get this error:

JavaScript runtime error: Object doesn't support property or method 'getColDef'

Perhaps I'm not doing this correctly? I'm fairly new at using Ag-Grid. Looking for suggestions.

tolsen64
  • 881
  • 1
  • 9
  • 22

5 Answers5

35

You are looking for setColumnState() and getColumnState(). See the docs at https://www.ag-grid.com/javascript-grid-column-api/

In your grid options, set up event handlers for gridReady and columnMoved. https://www.ag-grid.com/javascript-grid-events/

Something like:

gridOptions = {
   rowData: myRowDataSource,
   columnDefs: myColumns,
   onGridReady: onGridReady,
   onColumnMoved: onColumnMoved,
}

On the column moved event, save the columnState. Here's an example saved to local storage. Change it to save to your database.

onColumnMoved(params) {
  var columnState = JSON.stringify(params.columnApi.getColumnState());
  localStorage.setItem('myColumnState', columnState);
}

On the grid ready event, get and restore the grid State. Again, change this to pull from your database.

onGridReady(params) {
    var columnState = JSON.parse(localStorage.getItem('myColumnState'));
    if (columnState) {
      params.columnApi.applyColumnState(columnState, applyOrder:true);
    }
}

Updated answer based on comments from @Sebastian and @jsN00b.

Alien Technology
  • 1,760
  • 1
  • 20
  • 30
  • 8
    Just a hint if you just landed here: Since Version 24 setColumnState is deprecated and you should use columnApi.applyColumnsState({ state: savedState }); see https://www.ag-grid.com/javascript-grid-column-state/ – Sebastian Sep 30 '20 at 11:16
  • 3
    @Sebastian doesn't work for columns order – Simon Gerasimenko Mar 01 '22 at 14:20
  • 10
    @SimonGerasimenko & other members who may read this - one needs to add an additional prop when using `applyColumnState` namely `applyOrder: true;` as shown in [this example](https://www.ag-grid.com/javascript-data-grid/column-state/). – jsN00b Jul 08 '22 at 16:43
  • 1
    @jsN00b your comment saved me a few hours of pointless debugging. Thanks – LocustHorde Dec 15 '22 at 11:27
18

onColumnMoved will fire every time the column is moving but the drag didn't stopped.

Using onColumnMoved is not performant at all.

If you care about performance you should use onDragStopped

gridOptions.onDragStopped = function (params) {
  const colIds = params.columnApi.getAllDisplayedColumns().map(col => col.colId)
  console.log(colIds) // all visible colIds with the visible order
}
Roland
  • 24,554
  • 4
  • 99
  • 97
  • Very nice trick! its kinda frustrating seeing the store being modified repeatedly when you drag the column across the table. – NearHuscarl Jul 04 '20 at 17:45
  • 1
    Yes but the problem with this approach is that you need to capture columnMoved to get notified if the user resets the grid with the context menu. That doesn't cause a drag event. I think it makes more sense to get onColumnMoved and just debounce it. – DanH Dec 17 '20 at 20:06
4

My answer is a small improvement of @roli's answer. The event will only be fired if the column order has been changed after the operation. If the user drags and decides to stop and drops the column at the same index as before, the event will not be fired.

enter image description here

The code below is the implementation in react. The idea is simple: Store the column order as a list of colId when the drag started and compare it to the final column order when the drag stopped. The event will only be fired when there is a different between the 2 order.

function useDragColumnChange(cb: (e: DragStoppedEvent) => void) {
  const columnOrderRef = React.useRef<string[]>([])
  const onDragStarted = (e: DragStartedEvent) => {
    columnOrderRef.current = e.columnApi.getColumnState().map(c => c.colId);
  }
  const onDragStopped = (e: DragStoppedEvent) => {
    const newColumnOrder = e.columnApi.getColumnState().map(c => c.colId);
    const sameOrder = columnOrderRef.current.every(
      (c, i) => c === newColumnOrder[i]
    );

    if (!sameOrder) {
      cb(e);
    }
  }

  return { onDragStarted, onDragStopped };
}

Usage

// in render()

const { onDragStarted, onDragStopped } = useDragColumnChange(e => console.log('Saving new column order!'))

return (
  <AgGridReact
    ...
    onDragStarted={onDragStarted}
    onDragStopped={onDragStopped}
  />
);

Live Demo

Edit Column Reorder Event

NearHuscarl
  • 66,950
  • 18
  • 261
  • 230
  • This is nice and what I was using until I realised it doesn't capture the column move if the user resets their grid (and no other event handlers are invoked that you also have tied to the grid - e.g. if you reset with a sort then onSortChanged would fire). So if the reset just triggers a column order reset, this method doesn't work unfortunately. As per above I now just debounce the handlers for 500ms and do it the simple way. – DanH Dec 17 '20 at 20:08
0

 gridOptions: GridOptions ={
  onDragStopped:(
    event: DragStoppedEvent  
  ) =>  this.test(event)  
  }
  
  test(params){
let columnDragState = params.columnApi.getColumnState();
console.log(columnDragState, "columnDragState")
const colIds = params.columnApi.getAllDisplayedColumns().map(e=>{
  return e.colDef
});
console.log(colIds)

  let arr3 = colIds.map((item, i) => Object.assign({}, item, columnDragState[i]));
  console.log(arr3)
}
<ag-grid-angular
    style="width: 1500px; height: 750px; padding-top: 10px;"
    class="ag-theme-alpine"
    [columnDefs]="columnDefs"
    (gridReady)="onGridReady($event)"
    [rowDragManaged]="true"
    
    [gridOptions]="gridOptions"
    [rowData]="rowData"
>
</ag-grid-angular>
ramaeon2
  • 31
  • 4
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 25 '22 at 09:09
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 25 '22 at 12:38
0

In the following way we can update the column orders manually using onColumnMoved or onDragStopped event

const onDragStopped = useCallback(params => {
    if (params.target.childElementCount > 1) {
        const colIds = params.columnApi.getAllDisplayedColumns().map(col => col.colId) // get new order 
        const value = columns.sort((a, b) => colIds.indexOf(a.colId) - colIds.indexOf(b.colId)) // apply the new order
        if (gridParams) {
        setColumns(value) // update the new order
    }
}
}, [ gridParams, setColumns ])
KARTHIKEYAN.A
  • 18,210
  • 6
  • 124
  • 133