What is ag-Grid?

ag-Grid is a client-side JavaScript grid that can be integrated natively with any major framework.

This is one of many blog posts designed to prove why we call it "the best grid in the world".

ag-Mail

This example leverages some ag-grid features to produce an interface similar to the one you can see in Gmail. You can find a running example and its code below.

0 DEPENDENCIES (ONLY AG-GRID)
250 LINES OF PLAIN JS CODE TO PACK ALL THE FUNCTIONALITY

Open Source Code in Plunker


Summary of features used

What follows are the list of features that have been used from ag-grid and how they have been used for this particular example.  This blog post assumes that you know the basics to work with ag-grid, but if you don't you can find the following links helpful:

Documentation / Getting started (JS / React / Angular / Vue)

Cell Renderers

MIT/Free
Documentation: JS / React / Angular / Vue
More information on cell rendering: Cell Renderers / Cell Content
More information on registering components: Registering Components
More Cell Renderer Examples (available only to customers and trial users)

Cell Renderers are used in this example to fully customise the body of the row and to provide with the hover effect showing the buttons.

Creating a Cell Renderer is very simple, you can see this in main.js. Below you can find the main highlights for the Cell Renderers:

// main.js
// 1 associate cell renderer to column, in this case, we are only using the renderer
// for rows that are not groups, to see this in action, click on 'Group by Sender'
// you can see more about cellRendererSelector in the above link 'Cell Renderers'
{
    colId: 'subject',
    field: "subject",
    width: 1092,
    cellRendererSelector: (params) => params.node.group ? null : {component: 'hoverCellRenderer'},
},
    
// 2 register the component. More information in above link 'Registering Components'
components: {
	hoverCellRenderer: HoverCellRenderer,
},

// 3 create the actual component. More information in the links above for Cell Rendering
function HoverCellRenderer() {
}

HoverCellRenderer.prototype.init = function (params) {

Events/API

MIT/Free
Documentation: Grid Events, Grid API
More Grid Events Examples (available only to customers and trial users)

We are listening to several events from the grid to provide with the buttons as you hover over the rows, note how this work in combination with the cell renderers and how we also use events to load the email preview pane.

This is how we register the listeners:

// gridOptions
{
    ...,
    onCellMouseOver: onCellMouseOver,
    onCellMouseOut: onCellMouseOut,
    onRowClicked: onRowClicked,
    onRowSelected: onRowSelected,
    onFirstDataRendered: () => gridOptions.api.sizeColumnsToFit(),
},
    

Note how we can fetch an instance of the renderer that we provide, so that we can call a method into it:

function onCellMouseOver(event) {

    let renderer = event.api.getCellRendererInstances({
        rowNodes: [event.node],
        columns: ['from', 'subject'],
    })[0];

    if (renderer == null) return;
    renderer.showButton();

}

// [...]

HoverCellRenderer.prototype.showButton = function () {

Data updating

MIT/Free
Documentation: Updating Data
More Updating Data Examples (available only to customers and trial users)

In several places in the example we update data, for instance, we update the data for the grid when deleting emails.

The example uses deltaRowDataMode so that updates are done without resetting the state of the grid, this can be configured in gridOptions:

// gridOptions
{
    ...,
    deltaRowDataMode: true,
	getRowNodeId: function (data) {
        return data.id;
    },
},

This is an example of how we are using the API to update the data in the grid:

function onClickDeleteAll() {
    let selectedRowNodes = gridOptions.api.getSelectedNodes();
    gridOptions.api.updateRowData({remove: selectedRowNodes});
}    

Pagination

MIT/Free
Documentation: Pagination

Pagination can be enabled in the gridOptions:

// gridOptions
{
    ...,
    pagination: true,
    paginationAutoPageSize: true,
},

Quick Filter

MIT/Free
Documentation: Quick Filter

Quick Filter is enabled in this example to allow filtering on all the data based on data input.

The Quick Filter can be applied by calling the Grid's API:

<!-- index.html -->
<input type="search" id="filter-text-box" placeholder="Search mail" oninput="onFilterTextBoxChanged()">
// main.js
function onFilterTextBoxChanged() {
    gridOptions.api.setQuickFilter(document.getElementById('filter-text-box').value);
}

Styling

MIT/Free
Documentation: Cell Styling, Row Styling
More Styling examples (available only to customers and trial users)

Row Styling is used in this example to distinguish between which emails are read or unread, and if they are unread then the text is made bold and the background colour is changed.

There are several ways to style the grid, in this case we are using rowClassRules + some bespoke CSS:

// gridOptions
{
    ...,
    rowClassRules: {
        'email-read': function (params) {
            return params.node.group ? false : !params.data.read;
        },
    },
},
/* styles.css */
.ag-theme-material .email-read {
    font-weight: bold !important;
    background-color: white;
}

Row Selection

MIT/Free
Documentation: Row Selection, Range Selection
More Row Selection Examples (available only to customers and trial users)

As we are enabling checkboxes in this example, we also need to be able to select multiple emails. To achieve this, we enable Row Selection.

Row Selection can be enabled in the gridOptions as follows:

// gridOptions
{
    ...,
    rowSelection: 'multiple',
},

Row Grouping

Enterprise license users only
Documentation: Row Grouping
More Examples (available only to customers and trial users)

Row Grouping allows us to take all the data and group by a common property, in this example we have the button 'Group by Sender' which groups all the emails based on the sender.

Row Grouping can be enabled by providing configuration to both, the gridOptions and the colDef:

// gridOptions
{    
   autoGroupColumnDef: {
        checkboxSelection: true,
    },
    groupUseEntireRow: true,
},
    
// from colDef
{
    rowGroup: rowGroupFrom, // this is toggled by the button
}
       
// note how the row grouping by 'from' is toggled dynamically from 
//the buton 'Group by Sender'
function onBtGroupBySender() {
    if (!isDataGrouped) {
        gridOptions.api.setColumnDefs(columnDefsFactory(true));
        isDataGrouped = true;
    } else {
        gridOptions.api.setColumnDefs(columnDefsFactory(false));
        isDataGrouped = false;
    }
    gridOptions.api.sizeColumnsToFit();
}

What's Next

If you want to try ag-grid, you will also find how in our getting started guides Getting started (JS / React / Angular / Vue)

Happy coding!