AG-Grid Tutorial With Asp.Net Core Razor Pages - Part 1
Tags: dotnet, tutorial, javascript, beginners
Published: 2020-01-27 09:29:57

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.


![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/oulg8wwyfkkn5ea3du0y.jpg)
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*
```csharp
 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*
```csharp
 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 closing the head tag.

```html
    <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:*
```csharp
 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*
```html
@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*
```html
.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:
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/cb2aw74dknvh8yohg6ly.png)