DEV Community

Cover image for AG-Grid Tutorial With Asp.Net Core Razor Pages - Part 1
Zoltan Halasz
Zoltan Halasz

Posted on

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.

Alt Text
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; }    
    }
Enter fullscreen mode Exit fullscreen mode

b. Context for in-memory database, idem

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

        public DbSet<InvoiceModel> InvoiceTable { get; set; }
    }
Enter fullscreen mode Exit fullscreen mode

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.

    <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">
Enter fullscreen mode Exit fullscreen mode

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);
        }


    }
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode
  • 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>
Enter fullscreen mode Exit fullscreen mode

Column headers are defined by array:

 var columnDefs = [
        { headerName: "InvoiceNumber", field: "InvoiceNumber" },
        { headerName: "Amount", field: "Amount" },
        { headerName: "CostCategory", field: "CostCategory" },
        { headerName: "Period", field: "Period" },
    ];
Enter fullscreen mode Exit fullscreen mode

Sorting and filtering (basic) is setup by:

defaultColDef: {
            sortable: true,
            filter: true
        },
Enter fullscreen mode Exit fullscreen mode

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'
        }
Enter fullscreen mode Exit fullscreen mode

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

'./Index?handler=ArrayData'
Enter fullscreen mode Exit fullscreen mode

The final result will be:
Alt Text

Top comments (4)

Collapse
 
albertparent profile image
Albert Parent

Zoltan, Great post.

What approach would you use in the scenario where your business data must be secure and direct client, i.e. remote, access is not allowed. For example, my data is in a cloud environment where the web server is white listed to the database. The current usage pattern is we do everything server side and deliver fully rendered pages to the browser. All of the authorization is handled via ACLs, also stored in the database.

I do use restful APIs to access other vendors data, but that just moves the problem because they also use a whitelist pattern because they don't want to manage the security exposure. Plus Rest APIs tend to get fat over time as you have to accommodate every possible combination of accessing joined data.

Thanks, Albert

Collapse
 
zoltanhalasz profile image
Zoltan Halasz

Thanks for checking this article, it's a step in my learning, which began only 6 month ago for asp.net core. That's why I don't consider I have enough experience to answer your question. I wanted to use Ag-Grid to try out various JS datagrids, and it's a really nice solution. I simply use data in json format, as per their examples ag-grid.com/javascript-grid/#fetch....

Collapse
 
jghadiri profile image
j-ghadiri • Edited

hello
how to upgrade this sample for asp.net core MVC 3.1?
without razor pages and customize with cshtml page?

Collapse
 
zoltanhalasz profile image
Zoltan Halasz

you can just start a new MVC 3.1 project. and paste into the view the javascript part from my razor page. the ag-grid should be populated using a get endpoint from a controller.