How to alphabetic order toolpanel in Data Grid

Hi,
reading ag-grid documentation, it show how to order the toolPanel:

const columnDefs = [
  { headerName: "Athlete", field: "athlete" },
  { headerName: "Age", field: "age" },
  { headerName: "Country", field: "country" },
  { headerName: "Year", field: "year" },
  { headerName: "Date", field: "date" },
  { headerName: "Sport", field: "sport" },
];

const sortedColumnDefs = [...columnDefs].sort((a, b) => a.headerName.localeCompare(b.headerName));

const gridOptions = {
  columnDefs: columnDefs, 
  sideBar: {
    toolPanels: [
      {
        id: "columns",
        labelDefault: "Columns",
        labelKey: "columns",
        iconKey: "columns",
        toolPanel: "agColumnsToolPanel",
        toolPanelParams: {
          suppressSyncLayoutWithGrid: true, 
          columnLayout: sortedColumnDefs 
        }
      }
    ],
    defaultToolPanel: "columns"
  }
};

// Inicializar el grid
new agGrid.Grid(document.getElementById('myGrid'), gridOptions);

With that information I try to do that in servoy, but it throw multiples errors.

This is what I try to do.
First I have to order the columns:

var columnDefs=[],_sortedColumnDefs=[];

for (var i = 0; i < elements.grid.columns.length; i++) {
			columnDefs.push(elements.grid.getColumn(i));
		}
function sortByName(arr) {
			return arr.sort(function(a, b) {
		        var nameA = scopes.utl_convert.utl_parseHeaderTitle(a.headerTitle).toLowerCase();
		        var nameB = scopes.utl_convert.utl_parseHeaderTitle(b.headerTitle).toLowerCase();
		       
		        if (a.headerTitle && a.headerTitle.indexOf('%%')>-1)
		        if (nameA < nameB) {
		            return -1;
		        }
		        if (nameA > nameB) {
		            return 1;
		        }
		        return 0; // Son iguales
		    });
		}
		_sortedColumnDefs = sortByName(columnDefs);

Then I try to set in the gridOptions from the grid:

var sideBar= {
		    toolPanels: [
		      {
		        id: "columns",
		        labelDefault: "Columns",
		        labelKey: "columns",
		        iconKey: "columns",
		        toolPanel: "agColumnsToolPanel",
		        toolPanelParams: {
		          suppressSyncLayoutWithGrid: true,
				  suppressColumnSelectAll: true,
				  suppressColumnFilter:false,
				  suppressPivotMode: true,
				  suppressRowGroups: false,
				  suppressValues: true,
				  columnLayout: _sortedColumnDefs
		        }
		      }
		    ]
		  }
		elements.grid.gridOptions.sideBar = sideBar;

Does anyone know how to do it?

Servoy version 2024.3.3 -releaseNumber 3946 (builddate: 2024-07-26 09:16)
Servoy NG-Grid 2024.3.5

Hi,
has anyone been in this situation?
If you has a grid with a lot of fields is to difficult to find a field.
Is there any one from servoy who know how to do it?

hi,

your sortByName needs to be a client side js function, because that is used by aggrid in the browser, but now it is a servoy js function, so server side js;
you should use clientutils.generateBrowserFunction to create the client side js, have a look here: https://docs.servoy.com/reference/servo … tionstring

Hi,

I’ve finally found the answer:

Sort ColumnsToolPanel alphabetically — generic for all grids

Servoy 2025.03 / AG-Grid 33.x

If you want to sort the Columns Tool Panel alphabetically across all grids
without configuring each one individually, you can do it generically via
plugins.ngDataGrid.gridOptions using onGridReady and a browser function.

The key points:

  • onGridReady fires on every grid at init — perfect for a global hook.
  • toolPanelVisibleChanged waits until the user opens the panel, avoiding timing issues.
  • api.getToolPanelInstance('columns').setColumnLayout() is the correct AG-Grid 33 API.
  • Columns with suppressColumnsToolPanel: true are filtered out.
var sortToolPanelFn = clientutils.generateBrowserFunction(
    'function(params) {' +
    '  var api = params.api;' +
    '  if (!api) return;' +

    '  api.addEventListener("toolPanelVisibleChanged", function(e) {' +
    '    if (e.key !== "columns" || !e.visible) return;' +

    '    var cols = api.getColumns();' +
    '    if (!cols) return;' +

    '    var sortedLayout = cols' +
    '      .filter(function(col) {' +
    '        return col.getColDef().suppressColumnsToolPanel !== true;' +
    '      })' +
    '      .slice()' +
    '      .sort(function(a, b) {' +
    '        var na = (a.getColDef().headerName || a.getColDef().field || "").toLowerCase();' +
    '        var nb = (b.getColDef().headerName || b.getColDef().field || "").toLowerCase();' +
    '        return na.localeCompare(nb);' +
    '      })' +
    '      .map(function(col) {' +
    '        return { colId: col.getColId() };' +
    '      });' +

    '    var toolPanel = api.getToolPanelInstance("columns");' +
    '    if (toolPanel) toolPanel.setColumnLayout(sortedLayout);' +
    '  });' +
    '}'
);

plugins.ngDataGrid.gridOptions = {
    onGridReady: sortToolPanelFn
};

Place this code in onSolutionOpen or wherever you initialize
plugins.ngDataGrid.gridOptions.

:warning: Note: do not use api.setColumnsPinnedLeft() — that method does not
exist in AG-Grid 33 and will throw a TypeError.

1 Like

Hi,

I have improved the code. Additionally, it is better to handle this using the onFirstDataRendered event:

plugins.ngDataGrid.gridOptions = { onFirstDataRendered: sortToolPanelFn };
var sortToolPanelFn = clientutils.generateBrowserFunction(
		    'function(params) {' +
		    '  var api = params.api;' +
		    '  if (!api) return;' +
			' var isSorting = false;'+
		    
		    '  api.addEventListener("toolPanelVisibleChanged", function(e) {' +
		    '    if (e.key !== "columns" || !e.visible || isSorting) return;' +
	
		    '    var cols = api.getColumns();' +
		    '    if (!cols) return;' +
//		    ' console.log("sortToolPanelFn ejecutado para un grid");'+
		    '    var sortedLayout = cols' +
		    '      .filter(function(col) {' +
			'			var colDef = col.getColDef();'+
		    '        return colDef && colDef.suppressColumnsToolPanel !== true;' +
		    '      })' +
		    '      .slice()' +
		    '      .sort(function(a, b) {' +
		    '        var na = (a.getColDef().headerName || a.getColDef().field || "").toLowerCase();' +
		    '        var nb = (b.getColDef().headerName || b.getColDef().field || "").toLowerCase();' +
		    '        return na.localeCompare(nb);' +
		    '      })' +
		    '      .map(function(col) {' +
		    '        return { colId: col.getColId() };' +
		    '      });' +
	
		    '    var toolPanel = api.getToolPanelInstance("columns");' +
			'	 if (toolPanel && typeof toolPanel.setColumnLayout === "function") {'+
			'		try {'+
			'			isSorting = true;'+
			'			toolPanel.setColumnLayout(sortedLayout);'+
			'		} catch (err) {'+
			'			console.error("Error al ordenar el Tool Panel: ", err);'+
			'		} finally {'+
			'			isSorting = false;'+
			'		}'+
			'	 }'+
		    '    if (toolPanel) toolPanel.setColumnLayout(sortedLayout);' +
		    '  });' +
		    '}'
		);