Saturday, April 13, 2013

ASP.Net MVC & ExtJs Grid [with Paging, Remote Soring and Filtering features] & Entity Framework Code First

In this post I am going to show how I created an Ext JS Grid and set up Paging, Remote Sorting and Filter features.

I have shared code at Github, feel free to download it and use it in your project.

In this project I have used Entity Framework code first for data access. After you download project you need to set up DB server name accordingly in Web.Config for application to run successfully.

 


In my solution I have 6 projects which, which are described as below:
1)MvcApplication.Core : It contains all core classes which will be used by other layers.
2)MvcApplication.DAL : It contains Models, Repository, DB context which is used by Main Application.
3)NewMvcApplication : Its main application which has a Person page that shows all persons.

Others are Test projects , as I have not written any Unit Test, I wont be discussing about them.

Once you run application first time , It will create all Tables and DB, once the DB is created you can insert some dummy data in your table.

Now I am going to discuss main components of my solution.
1) Persongrid.js  : It contains Javascript code which creates Person grid and sets up filter, Paging toolbar which is used by Grid. Here is the content of that file, As you can see here first I am creating a Data store, then using that Data store to create my ExtJs grid. I am also creating Paging toolbar to show my page numbers. I also specify filter information while defining columns.


Ext.Loader.setConfig({ enabled: true });

Ext.require([
    'Ext.grid.*',
    'Ext.data.*',
    'Ext.ux.grid.FiltersFeature',
    'Ext.toolbar.Paging',
    'Ext.ux.ajax.JsonSimlet',
    'Ext.ux.ajax.SimManager'
]);


Ext.onReady(function () {

    Ext.define('Person', {
        extend: 'Ext.data.Model',
        fields: [
        { name: 'FirstName', type: 'string' },
        { name: 'FirstName', type: 'string' },
        { name: 'MI', type: 'string' },
        { name: 'LastName', type: 'string' },
        { name: 'FaceBookId', type: 'string' },
        { name: 'Email', type: 'string' },
        { name: 'TwitterId', type: 'string' },
        { name: 'LinkedInId', type: 'string' },
        { name: 'BlogUrl', type: 'string' }
        ]
    });

    var store = Ext.create('Ext.data.Store', {
        model: 'Person',
        remoteSort: true,
        proxy: {
            type: 'ajax',
            url: '/Person/ListExtJs',
            reader: {
                type: 'json',
                root: 'data',
                totalProperty: 'totalCount'
            }
        },
        autoLoad: true,
        
    });

    // configure whether filter query is encoded or not (initially)
    var encode = true;

    // configure whether filtering is performed locally or remotely (initially)
    var local = true;

    var filters = {
        ftype: 'filters',
        encode: encode, 
        local: false
    };

    var grid = new Ext.grid.GridPanel({
        store: store,
        columns: [
           { header: 'Id', dataIndex: 'Id', hidden: true},
           { header: 'First Name', dataIndex: 'FirstName', width: 100, filterable:true },
           {
               header: 'Middle Initial', dataIndex: 'MI', width: 100
           },
           { header: 'Last Name', dataIndex: 'LastName', width: 100 },
           {
               header: 'FaceBook Id', dataIndex: 'FaceBookId', width: 100,
               filter: {
                   type: 'string'
                   // specify disabled to disable the filter menu
                   //, disabled: true
               }
           },
           {
               header: 'Email', dataIndex: 'Email', width: 100,
               filter: {
                   type: 'string'
                   // specify disabled to disable the filter menu
                   //, disabled: true
               }
           },
           {
               header: 'TwitterId', dataIndex: 'TwitterId', width: 100,
               filter: {
                   type: 'string'
                   // specify disabled to disable the filter menu
                   //, disabled: true
               }
           },
           { header: 'LinkedInId', dataIndex: 'LinkedInId', width: 100 },
           { header: 'BlogUrl', dataIndex: 'BlogUrl', width: 200 }
        ],
        
        renderTo: 'grid',
        width: 1000,
        autoHeight: true,
        bbar: new Ext.PagingToolbar({
            store: store,
            pageSize: 5,
            displayInfo: true,
            displayMsg: 'Displaying employees {0} - {1} of {2}',
            emptyMsg: "No employees to display"
        }),
        pageSize: 25,
        title: 'Employees',
        features: [filters],
    });
                
    grid.getStore().load({ params: {
        start: 0,
        limit: 25
    }
    });
});


2) I have added following method in my Person controller, here I am based on requested data I use filter and  sort data to return requested data.


      public ActionResult ListExtJs(int start, int limit,string sort, string filter)
        {
            int totalcount = db.Persons.Count();
            List<FilterData> filters;
            List<SortData> sorts;
            List<Person> persons;

            filters = FilterData.GetData(filter);
            sorts = SortData.GetData(sort);
            if (sorts.Count() == 0)
            {
                sorts.Add(new SortData() { direction = "ASC", property = "FirstName" });
            }
            string sortproperty = sorts[0].property;
            string sortdirection = sorts[0].direction;

            persons = db.Persons.Where(FilterData.GetWhereCriteria(filters)).OrderBy(sortproperty + " " + sortdirection).Skip(start).Take(limit).ToList();
            
            return Json(new { data = persons.ToArray(), totalCount = totalcount }, JsonRequestBehavior.AllowGet);

        }


3) I have created FilterData and SortData classes which are present in MvcApplication.Core they are class representation of data passed from ExtJs grid while loading data.



You can download this code from github using this link.