Saturday, January 25, 2020

AG-Grid Tutorial With Asp.Net Core Razor Pages - Part 1


Besides DataTables.js, I always wanted to check Ag-Grid, which is another great Javascript Grid solution for the front-end. As my apps are from the business world, and have many tables, I wanted to see how AG-Grid would look like in Asp.Net Razor pages.


I quickly checked their Javascript documentation, and prepared a short tutorial, firstly for myself.
The material is based on the existing Datatables tutorial, from my previous posts. It uses an in-memory database and context, injected in the page model.

Please check the following, before starting the tutorial:
1. general introduction: https://www.ag-grid.com/javascript-grid/
2. see previous tutorial, which this one builds upon: https://mydev-journey.blogspot.com/2019/12/datatablejs-tutorial-for-net-core-razor_11.html
3. working example of the tutorial: https://ag-grid1.zoltanhalasz.net/
4. code repo for the tutorial:(zipped) https://drive.google.com/open?id=1BXYkn5RwHnC4w8USCeIBCV0lsDGi-qFh

Explanation of the project:
a. Base class for the application, identical with datatable tutorial above
 public class InvoiceModel
    {
        [JsonProperty(PropertyName = "ID")]
        public int ID { get; set; }

        [JsonProperty(PropertyName = "InvoiceNumber")]
        public int InvoiceNumber { get; set; }

        [JsonProperty(PropertyName = "Amount")]
        public double Amount { get; set; }
        [JsonProperty(PropertyName = "CostCategory")]
        public string CostCategory { get; set; }
        [JsonProperty(PropertyName = "Period")]
        public string Period { get; set; }
     

    }
b. Context for in-memory database, idem

 public class InvoiceContext : DbContext
    {
        public InvoiceContext(DbContextOptions<InvoiceContext> options)
            : base(options)
        {
        }

        public DbSet<InvoiceModel> InvoiceTable { get; set; }
    }

c. In the Pages/Shared folder, we will edit the _Layout page
insert the following stylesheet links specific to AG-grid, just before </head>
    <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">

d. The index page, will have the following methods:

 public class IndexModel : PageModel
    {
        private InvoiceContext _context;

        public List<InvoiceModel> InvoiceList;
        public IndexModel(InvoiceContext context)
        {
            _context = context;
        }

        // this will populate the page, if you want to show the table using the list (with foreach)
        public async Task<IActionResult> OnGet()
        {
            InvoiceList = _context.InvoiceTable.ToList();
            return Page();
        }

        //method to provide list in json format, for the ag-grid
        public JsonResult OnGetArrayData()
        {
            InvoiceList = _context.InvoiceTable.ToList();

            return new JsonResult(InvoiceList);
        }


    }

e. the html razor file, will contain the javascript code, based on the tutorial from ag-grid page
@page
@model IndexModel
@{
    Layout = "_Layout";
}

@*//script used to load the grid*@
<script src="https://unpkg.com/ag-grid-community/dist/ag-grid-community.min.noStyle.js"></script>
<h1>Hello from ag-grid!</h1>

<div id="myGrid" style="height: 600px;width:800px;" class="ag-theme-balham"></div>

<script type="text/javascript" charset="utf-8">
    // specify the columns
    var columnDefs = [
        { headerName: "InvoiceNumber", field: "InvoiceNumber" },
        { headerName: "Amount", field: "Amount" },
        { headerName: "CostCategory", field: "CostCategory" },
        { headerName: "Period", field: "Period" },
    ];

    // let the grid know which columns to use
    var gridOptions = {
        columnDefs: columnDefs,
        defaultColDef: {
            sortable: true,
            filter: true
        },
        rowClassRules: {
        // row style function
            'bigexpense-warning': function(params) {
                var numExpense = params.data.Amount;
                return  numExpense > 20 && numExpense <= 50;
            },
            // row style expression
            'bigexpense-breach': 'data.Amount > 50',
            'bigexpense-ok': 'data.Amount <=20'
        }
    };

    // lookup the container we want the Grid to use
    var eGridDiv = document.querySelector('#myGrid');

    // create the grid passing in the div to use together with the columns & data we want to use
    new agGrid.Grid(eGridDiv, gridOptions);

    agGrid.simpleHttpRequest({ url: './Index?handler=ArrayData' }).then(function (data) {
        gridOptions.api.setRowData(data);
    });

</script>

f. create the gridformat.css file in the folder wwwroot/css
include the following in this file
.ag-theme-balham .bigexpense-warning {
    background-color: sandybrown !important;
}

.ag-theme-balham .bigexpense-breach {
    background-color: lightcoral !important;
}

.ag-theme-balham .bigexpense-ok {
    background-color: mediumseagreen !important;
}

- in order to be able to populate the rowClassRules with valid css formatting classes
- include the reference to gridformat.css in the _Layout file, just above the ag-grid css links

g. some description of the javascript in the index.cshtml

Grid is marked by id:

<div id="myGrid" style="height: 600px;width:800px;" class="ag-theme-balham"></div>
Column headers are defined by array:
 var columnDefs = [
        { headerName: "InvoiceNumber", field: "InvoiceNumber" },
        { headerName: "Amount", field: "Amount" },
        { headerName: "CostCategory", field: "CostCategory" },
        { headerName: "Period", field: "Period" },
    ];
Sorting and filtering (basic) is setup by:
defaultColDef: {
            sortable: true,
            filter: true
        },

Double click on the row headers will sort the column.
There is a basic text filter included.

The formatting of rows, where the invoice Amount is between certain values
 rowClassRules: {
        // row style function
            'bigexpense-warning': function(params) {
                var numExpense = params.data.Amount;
                return  numExpense > 20 && numExpense <= 50;
            },
            // row style expression
            'bigexpense-breach': 'data.Amount > 50',
            'bigexpense-ok': 'data.Amount <=20'
        }

If you check the simpleHttpRequest function it's called on the handler defined in the pagemodel of the index page:

'./Index?handler=ArrayData'

The final result will be:


No comments:

Post a Comment