ExtJS and MVC : 06 - Implementing the GridPanel

This website is no longer actively supported

Written by John DeVightJohn DeVight on 15 Jun 2011 18:45

Download RAZOR Source Code
Download ASPX Source Code
* Note: the extjs folder has all been removed to reduce the zip file size


In the wiki article ExtJS and MVC : 04 - Load and Save an HTML Form Using AJAX I showed how a form can be loaded and saved using AJAX. I wanted to be able to do the same thing with a GridPanel. The GridPanel uses an Ext.data.Store just like the Ext.form.ComboBox did in the wiki article ExtJS and MVC : 05 - ExtJS ComboBox vs. MVC DropDownList. However, the Ext.data.JsonStore that I implement requires some additional config options to support saving the modified records in the Store. In the example, I create an edit form so that when a user clicks on a row in the grid, the information for the selected record is displayed in a form for the user to edit and update. Instead of updating the record as soon as it is edited, I wait until the user clicks the save button to save all the modified data at the same time.

I added to the existing code from the ExtJS and MVC : 05 - ExtJS ComboBox vs. MVC DropDownList where I display a view with information about a series of wiki pages. The GridPanel that I add is to display a list of wiki pages related to the wiki series. When the user clicks on a wiki page in the grid, an edit form is displayed in a frameset. When the user clicks on the Update button in the frameset, the record in the JsonStore is updated and reflected in the GridPanel. When the user clicks on the Save button the wiki series information is saved, and then the modified wiki pages are saved.

Screenshot of GridPanel and "edit" Form

ExtJS Code

Creating the JsonStore for the GridPanel

In the JsonStore I set the following config options:

  • root - The JsonStore calls the HomeController.GetWikiPages method to get a list of wiki pages. The JsonStore looks for the list of wiki pages to be in a "root" property that contains the array of wiki pages. The reason this is needed is because the "root" property is the parameter name that is used when the JsonStore saves the array of updated wiki pages. If the "root" property is not specified, the JsonStore uses a parameter name of "undefined" for the array of updated wiki pages.
  • idProperty: Identifies the property in the wiki page object that uniquely identifies the object.
  • fields: list of properties defined in a wiki page object.
  • writer: an Ext.data.JsonWriter object with configured to send the entire record of the updated wiki pages to the server as a JSON array.
  • proxy: an Ext.data.HttpProxy that defines the URL's to use for the load and update of the records.
  • storeId: the Id for the JsonStore.
  • autoSave: set to false indicating that the save function must be manually called to send the modified records to the server.

After the JsonStore is instantiated, the load function is called to load the JsonStore.

Here is the code:

var wikiPagesStore = new Ext.data.JsonStore({
    // url: '/Home/GetWikiPages/' + Ext.getDom('Id').value,
    root: 'WikiPages',
    idProperty: 'Id',
    fields: ['Id', 'WikiSeriesId', 'Name', 'Url', 'PageViews', 'UniquePageViews'],
    writer: new Ext.data.JsonWriter({
        encode: true,
        listful: true,
        writeAllFields: true
    proxy: new Ext.data.HttpProxy({
        // prettyUrls: false,
        api: {
            read : { url: '/Home/GetWikiPages/' + Ext.getDom('Id').value, method: 'GET' },
            update : { url: '/Home/SaveWikiPages', method: 'POST' }
    storeId: 'wikiPagesStore',
    autoSave: false

Creating the GridPanel

In the GridPanel, I set the following config options:

  • store: the name of the JsonStore that contains the data to be displayed in the grid.
  • singleSelect: set to true to indicate that only one row can be selected at a time.
  • autoScroll: set to true to let the GridPanel handle showing scrollbars as needed.
  • height: the height for the grid.
  • columns: an array of column settings. I set the following config options for each column:
    • header: text to be displayed in column heading.
    • width: width of the column.
    • dataIndex: the name of the field to display in the column as defined in the JsonStore's fields list.
  • listeners: list of event listeners. The event that I define a listener for is the rowclick event. The function that is executed gets the record from the JsonStore and calls the editWikiPage function to display the data in the record in the "edit" form.

After the GridPanel is instantiated, the render function is called to display the GridPanel. In the view, I put a div where I want the GridPanel to appear and I gave it an id of wikiPagesGridPanel. I pass the id of the div to the render function so that the GridPanel can be rendered inside the div.

Here is the html for the div:

<div id="wikiPagesGridPanel"></div>

Here is the code for the GridPanel:

var wikiPagesGridPanel = new Ext.grid.GridPanel({
    store: wikiPagesStore,
    singleSelect: true,
    autoScroll: true,
    height: 150,
    columns: [{
        header: 'Name',
        width: 450,
        dataIndex: 'Name'
    }, {
        header: 'URL',
        width: 450,
        dataIndex: 'Url'
    }, {
        header: 'Page Views',
        width: 75,
        dataIndex: 'PageViews'
    }, {
        header: 'Unique Page Views',
        width: 125,
        dataIndex: 'UniquePageViews'
    listeners: {
        rowclick: {
            fn: function(grid, rowIndex, e) {
                // Get the data from the store.
                var rec = wikiPagesStore.getAt(rowIndex);
                // Display the data for editing.

Editing the Wiki Page Record

In the view, I define a div that contains a framset. The div is hidden by default. The framset contains the input fields for editing a wiki page record and a div where the update button is displayed. The update button has an id of updateWikiPageButton.

The GridPanel implements the rowclick event listener and calls the editWikiPage function. The editWikiPage function displays the div that contains a frameset with the "edit" form and sets all the values in the input text elements. To get the input text elements so that I can set the value, I use the Ext.getDom function.

editWikiPage = function(rec) {
    // Show the edit div.
    Ext.getDom('wikiPageEditDiv').style.display = '';
    // Display the row data for editing.
    Ext.getDom('selectedWikiPageId').value = rec.get('Id');
    Ext.getDom('nameTextBox').value = rec.get('Name');
    Ext.getDom('urlTextBox').value = rec.get('Url');
    Ext.getDom('pageViewsTextBox').value = rec.get('PageViews');
    Ext.getDom('uniquePageViewsTextBox').value = rec.get('UniquePageViews');

When the user is finished editing the wiki page and clicks the update button, the function defined in the update button's handler gets executed. The function gets the record from the JsonStore. The record.beginEdit function is called first. Then the record values are set. Next, the record.endEdit is called that notifies the JsonStore that the record has been updated. Finally the div that contains the frameset and the "edit" form is hidden.

Here is the code that creates the update button and defines the function for the button's handler:

var updateWikiPageButton = new Ext.Button({
    text: 'Update',
    applyTo: 'updateWikiPageButton',
    handler: function (sender, e) {
        // Save the changes to the wiki page.
        var rec = wikiPagesStore.getById(Ext.getDom('selectedWikiPageId').value);
        rec.set('Name', Ext.getDom('nameTextBox').value);
        rec.set('Url', Ext.getDom('urlTextBox').value);
        rec.set('PageViews', Ext.getDom('pageViewsTextBox').value);
        rec.set('UniquePageViews', Ext.getDom('uniquePageViewsTextBox').value);
        // Hide the edit div.
        Ext.getDom('wikiPageEditDiv').style.display = 'none';

Saving the Modified Wiki Pages

To save the modified wiki pages, I call the JsonStore.save() function. I implement this in the save button's handler after I call the Ext.Ajax.request to save t he WikiSeries and get a successful response.

Here is the code:

var saveButton = new Ext.Button({
    text: 'Save',
    applyTo: 'saveButton',
    handler: function (sender, e) {
        var formData = Ext.lib.Ajax.serializeForm(Ext.get('wikiForm'));
            method: 'POST',
            url: '/Home/Save',
            params: formData,
            success: function(response) {
                var responseObj = Ext.decode(response.responseText);
                if (responseObj.result == "success") {
                    // alert('Successfully Saved');
                else {
            failure: function() {

C# Code

Getting the List of Wiki Pages

In the HomeController I created a method called GetWikiPages that returns a JsonResult. I get the list of wiki pages from a property in the HomeController called WikiPageList. I then use Linq to Objects to get the wiki pages based on the wiki series id passed in.

In the JsonStore, I specified a "root" property that contains the array of wiki pages. The "root" property is "WikiPages". In the Controller.Json function, I create a new object and set the WikiPages property to the list of wiki pages.

Here is the code:

public JsonResult GetWikiPages(int id)
    var wikiPages = (from WikiPage wp in this.WikiPageList
                        where wp.WikiSeriesId == id
                        select wp);
    return Json(new { WikiPages = wikiPages }, JsonRequestBehavior.AllowGet);

Saving the List of Modified Wiki Pages

I created a method in the HomeController called SaveWikiPages. The method has a string parameter called WikiPages. The parameter name corresponds to the "root" property specified in the JsonStore. The WikiPages parameter is a string representation of an array of JSON objects where each JSON object is a wiki page. I use the System.Web.Script.Serialization.JavaScriptSerializer class to deserialize the string into a list of wiki page objects. For each wiki page object, I persist the changes to the wiki page list defined in the HomeController.WikiPageList property.

Here is the code:

public void SaveWikiPages(string WikiPages)
    JavaScriptSerializer serializer = new JavaScriptSerializer();
    IList<WikiPage> wikiPageUpdatedList = serializer.Deserialize(
        WikiPages, typeof(List<WikiPage>)) as IList<WikiPage>;
    IList<WikiPage> list = this.WikiPageList;
    foreach (WikiPage updatedWikiPage in wikiPageUpdatedList)
        WikiPage persistedWikiPage = (from WikiPage wp in list
                                        where wp.Id == updatedWikiPage.Id
                                        select wp).FirstOrDefault();
    this.WikiPageList = list;


Discussion Closed

Add a New Comment

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License