Practical ASP.NET

Updating Rows with a Client-side Grid

Peter continues exploring incorporating client-side JavaScript controls into ASP.NET applications -- and runs into what appears to be a brick wall when he tries to implement updates.

This series began with a discussion in an earlier column about the best way to incorporate a grid into an ASP.NET MVC application (assuming you don't want to write all the JavaScript yourself). I suggested that the right answer would be to use a client-side grid. In my last column, I used the client-side grid from the ExtJs package to display two columns in a grid. This column moves on from there to look at implementing updates using that client-side grid. But I'll warn you right now: This doesn't end as well as I would like.

My goal in this project is to use as little custom code as possible. Ideally, I want to link together a set of configured objects (as I would with ASP.NET server-side controls) and have them "do the right thing". In this case, the right thing is to allow the user to change data in the grid and then have those changes sent back to a Web Service to update the database.

Starting with my code from the last column, I first made the changes to support updates. I upgraded the code that I use to configure my HttpProxy (which handles communication with my Web services) with a more sophisticated configuration that uses the HttpProxy's api property to specify separate services for reading and updating:

proxyCustomer = new Ext.data.HttpProxy({
    api: {read : "NorthwindCustomers.asmx/GetCustomers",
          update: "NorthwindCustomers.asmx/UpdateCustomer"
          },
    headers: {"Content-type": "application/json" },
    method: "POST"                   
       });

Since I'm going to be writing data back to the server as JSON objects, I need to create a JsonWriter to send data back through the proxy. I don't need to configure this object (the defaults are fine), but I need to configure my dataStore to use it:

writeCustomer = ew Ext.data.JsonWriter({});
                        
dsCustomer = new Ext.data.Store({
    id: "dsCustomer",
    proxy: proxyCustomer,
    reader: readerCustomer,
    writer: writeCustomer,
    autoSave: false
       });

In the dataStore, setting autoSave to false allows me to control when updates are sent back to the server.

The next step is to make selected columns in the EditGridPanel that I'm using editable. I do that in the ColumnModel object that defines the columns in the grid. For each column that I want to let the user update, I specify an editor. In this case, I'm only supporting editing for the ContactName column:

colCustomer = new Ext.grid.ColumnModel([
	{header: "Customer ID", 
	 dataIndex: "CustomerId"
      },
	{header: "Contact Name", 
	 dataIndex: "ContactName", 
	 editor: {
	     xtype: 'textfield',
	     allowBlank: false
	          }
	}
	]);

With this change, if the user double-clicks the cell in the grid, he or she will be able to change the cell's contents.

To trigger sending data back to the Web service I specified in my HttpProxy, I add an HTML button to the page and tie a JavaScript function to the button's onclick event. In the JavaScript function, I call the save method on my dataStore:

<input type="button" onclick="return saveCustomers();" 
    value="Save Customers" id="btnSaveCustomers"/>

function saveCustomers() {
    dsCustomer.save();
        }

I'm using a class I've called CustomerDTO to move data between my Web service and the JavaScript in my browser (to simplify my server-side layer, I just used Entity Framework to create my middle tier objects and I use CustomeDTO to avoid returning EF objects to the client). I needed to be more specific about how I wanted CustomerDTO serialized on its journey down and back to the browser, so I added DataContract and DataMember attributes to it:

Imports System.Runtime.Serialization

<Serializable()> _
<DataContract()> _
Public Class CustomerDTO
... 
<DataMember()> _
    Public Property ContactName() As String
... 
<DataMember()> _
    Public Property CustomerId() As String
... 

In the Web service, I receive the JSON object from the client as a string (to support the convention used when returning JSON objects, the parameter for my method must be called "d"). Once I receive the string from the client, I use the JavaScriptSerializer to convert it into an array of CustomerDTO objects:

Imports System.IO
Imports System.Web.Script.Serialization
... 
<WebMethod()> _
Public Sub UpdateCustomer(ByVal d As CustomerDTO)
Dim cDTOs() As CustomerDTO

  Dim js As New JavaScriptSerializer
  cDTOs = js.Deserialize(Of CustomerDTO())(d)
            

I then loop through the resulting array and, for each CustomerDTO, I retrieve the corresponding entity from my Entity Framework using a LINQ query. After retrieving the entity I update it with data from the CustomerDTO I received from the client. Finally, I save my changes:

Dim nw As New northwndModel.northwndEntities
  For Each cDTO As CustomerDTO In cDTOs
    Dim cust = (From c As northwndModel.Customers _
              In nw.Customers _
              Where (c.CustomerID = CustDTO.CustomerId) _
              Select c).First
    cust.ContactName = CustDTO.ContactName
  Next

  nw.SaveChanges()

The code is a little bit more complicated than I show here because I have to handle those situations where the user only updates a single entry. But it works... provided that I'm using FireFox as my browser. In Internet Explorer, I can't seem to get my Web service called. I'm open to suggestions if anyone has any, but I suspect that the problem is related to trying to use an ASMX file for my Web service. I need something more up-to-date.

So, in my next column I'll start looking at two alternatives to the technology set I used here: ASP.NET MVC and WCF.

About the Author

Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.

comments powered by Disqus

Featured

Subscribe on YouTube