<!DOCTYPE html>
<html>
    <head>
        <script src="https://unpkg.com/ag-grid-community/dist/ag-grid-community.min.noStyle.js"></script>
        <link rel="stylesheet" href="https://unpkg.com/ag-grid-community/dist/styles/ag-grid.css">
        <link rel="stylesheet" href="https://unpkg.com/ag-grid-community/dist/styles/ag-theme-balham.css">
    </head>
<body>
<h1>Hello from ag-grid!</h1>
<div id="myGrid" style="height: 500px; width:700px;" class="ag-theme-balham"></div>

<script src="number-formatter.js"></script>
<script src="numeric-editor.js"></script>
<script src="range-filter.js"></script>

<script type="text/javascript" charset="utf-8">

    const columnDefs = [
        {headerName: 'Make', field: 'make'},
        {headerName: 'Model', field: 'model'},
        {
            headerName: 'Price',
            field: 'price',
            editable: true,
            cellRenderer: 'numberCellFormatter',
            cellEditor: 'numericCellEditor',
            filter: 'rangeFilter',
        }
    ];

    const gridOptions = {
        columnDefs: columnDefs,
        enableSorting: true,
        enableFilter: true,
        components: {
            numberCellFormatter: NumberCellFormatter,
            numericCellEditor: NumericCellEditor,
            rangeFilter: RangeFilter
        }
    };

    const eGridDiv = document.querySelector('#myGrid');

    new agGrid.Grid(eGridDiv, gridOptions);

    fetch('https://www.ag-grid.com/example-assets/row-data.json').then(function (response) {
        return response.json();
    }).then(function (data) {
        gridOptions.api.setRowData(data);
    })

</script>
</body>
</html>
# JavaScript AG Grid Customization Demo

A quick demo of customizing AG Grid with JavaScript to have custom filters, editors and cell renderers.

Blog:

https://blog.ag-grid.com/learn-to-customize-javascript-grid-in-less-than-10-minutes/

Code:

https://github.com/ag-grid/javascript-data-grid/tree/main/customization-demo
class NumberCellFormatter {
    init(params) {

        const text = params.value.toLocaleString(undefined, {style: 'currency', currency: 'EUR'});

        this.eGui = document.createElement('span');
        this.eGui.innerHTML = text;
    }

    getGui() {
        return this.eGui;
    }
}
class NumericCellEditor {
    init(params) {
        this.textInput = document.createElement('input');
        this.textInput.value = params.value;

        this.textInput.addEventListener('keypress', (event) => {
            if (!isNumeric(event)) {
                event.preventDefault();
            }

            function isNumeric(event) {
                return /\d/.test(event.key);
            }
        });

        this.textInput.addEventListener('keydown', (event) => {
            if (event.keyCode === 39 || event.keyCode === 37) {
                event.stopPropagation();
            }
        });
    }

    getGui() {
        return this.textInput;
    }

    afterGuiAttached() {
        if (this.textInput) this.textInput.focus();
    };

    getValue() {
        return Number(this.textInput.value);
    };
}
class RangeFilter {
    init(params) {
        this.params = params;

        this.filter = '';

        this.form = document.createElement('form');
        this.input = document.createElement('input');
        const button = document.createElement('button');

        this.form.appendChild(this.input);
        this.form.appendChild(button);

        this.input.name = 'filter';
        this.input.value = this.filter;
        button.textContent = 'Apply';

        this.form.addEventListener('submit', (event) => {
            event.preventDefault();

            let filter = event.target.elements.filter.value;

            if (this.filter !== filter) {
                this.filter = filter;
                this.params.filterChangedCallback();
            }
        });
    }

    getGui() {
        return this.form;
    }

    isFilterActive() {
        return this.filter !== '';
    }

    doesFilterPass(params) {
        const filter = this.filter.split('-');
        const gt = Number(filter[0]);
        const lt = Number(filter[1]);
        const value = this.params.valueGetter(params.node);

        return value >= gt && value <= lt;
    }

    getModel() {
        return {filter: this.filter};
    }

    setModel(model) {
        this.filter = model ? model.filter : '';
    }

    afterGuiAttached(params) {
        this.input.focus();
    }
}