Building On-the-fly functionality into a Datagrid


Keywords: .Net Framework

Not too long ago I was confronted with the task of building a Datagrid, with one of it’s columns containing input fields that could hold monetary values. These input fields would allow for a user to change the values within them, resulting in a realtime recalculation of the sum of all visible input field values. The result of this would be displayed at the bottom of the grid. – all of this, without a postback of any kind. After trying endlessly to google a solution for it, I gave up and faced the drudgery of building it myself. Here's how I did it.


The magic encompassing this particular exercise can be summarized in one word – Javascript. Let’s start by breaking down this project into steps. Bear in mind that this is not yet a custom web control so all the code takes place in a web form and it’s codebehind.

Designing your Datagrid
For the most part, the Datagrid we need is no different from your average Datagrid. The main differences is our updateable input field column. The total field that stores the sum of all our updateable input fields is nothing new, and there are countless tutorials on how to rig one up. While we’re on the presentation layer, however, I might add that another crucial element that adds support for the features this article discusses are a horde of hidden fields. I use six in all, to support the control.
 I prefer to use textboxes styled to not appear on the page rather than "<input type=”hidden”/>" fields, for the simple reason that I can choose to see their contents when I please, allowing me to better debug my code. In using hidden textboxes, you should try to avoid using display:none or visibility:hidden css tags for these fields, for reasons that are beyond the scope of this article. Instead set border, height and width to 0px. These are the ones I used:

txtHiddenTotalLabelName
This stores the ID of the Total Label which exists within the Datagrid. The label will hold the calculated sum of the input field columns of our grid. We just can’t hardcode that ID into this hidden field because the Datagrid control implements the InamingContainer interface which assigns unique ID’s to child controls.

txtHiddenTotalValue
Aside from storing our total value at the bottom of the Datagrid, we also need a place where we can just store it as a regular unformatted numeric value, this field does that job.

txtHiddenCurrentValue
Once you set focus on one of our Datagrid input fields to begin manipulating it’s value, we store that initial value in a safe place to use for further calculations. Keep reading to find out why and how exactly we do this.

txtHiddenLastTextFieldID
This last hidden field will store the ID for the last input field whose value we manipulated.

Retrieving and Binding Data
You are free to bind data from any datasource to the grid. The only requirement needed for this project to be meaningful is for you to have one field that holds monetary values -- that is the value that we are going to be adding up, once a user changes it. For the purposes of this tutorial, I use a for loop to create my own data source using a method called GetTestData();

Writing your Javascript
This is probably the most intense part of the entire process. We need several Javascript functions to do summation, and validation of input values. The table below gives a gist of what we need on the javascript side.
__StoreCurrentValue():void
This method gets triggered on the 'onFocus' event of the input field inside the Datagrid, whose value is being changed at the moment. It is basically the 'caching' function that we use to store the value in the input field before it is changed.

__ReCalculateTotal():void
This method gets trigerred on the 'onBlur' method of the input field inside the Datagrid whose value has most recntly either been changed or attempted to be changed.

LastValueWasValid():bool
This is our validation manager method. It performs all the necessarry validation we need on the values entered into our input fields.
The flow of control goes like so:

Exciting isn't it? By this point, a lot of the drama is out of the way, but we're not quite there yet. Why you say? Well, what happens when a user changes a page in the Datagrid? Remember that typcially this means retrieving our data from data storage once again and re-binding it to the Datagrid. Unfortunately, when we go to retrieve our data, it will not have the changes we have made. We have to find a way to persist our data across postbacks, which brings us to our next item.

Persisting changes made to data
The simple solution for persisting our changes made inside the grid is to store our datasource, once we retrieve it to either a page cache or Viewstate so that on every event that causes a postback, we update our cached datasource and then re-bind our grid. I chose the Viewstate in this example. The only column inside the grid, whose values change and hence need to be tracked are those in our input field column. I use a method in my codebehind called 'UpdateTableRows' that retrieves a reference of my stored datatable from the ViewState, updates the rows with newly inputed values and then re-binds it to my grid. This method is called on all events that cause a postback.

private System.Data.DataTable UpdateDataTableRows(DataGrid dg)

        {           

            System.Data.DataTable _dt = (System.Data.DataTable)this.ViewState[StoredTable];

            int currIndex=0;

            foreach (DataGridItem item in dg.Items)

            {

                currIndex = Convert.ToInt32(dg.DataKeys[item.ItemIndex].ToString());

                _dt.Rows[currIndex]["PaymentAmount"] = ((TextBox)item.FindControl("AmtInput")).Text;

                _dt.AcceptChanges();

            }

            return _dt;

        }



Submitting Data
What you do with your data after clicking submit is really up to you. Just remember that, just like with the pageIndexChanged event, the submit button causes a postback, and hence must have code in the event to persist all changes made to the cached datastore.
Download the code and play around with it to get the clearer picture. At the very least, this article should provide you with the very much needed javascript required to make this clock tick.  

 
Comment:*  Fields marked (*) are required.

Posted By:*  

Website:(requires 'http://' if entered)  

Email:* (Not displayed)    
 


Past Postings

From:
To:

Subscribe

       

Home | About | Portfolio | Favorites | Design Tips | Contact
Designed by Jonathan Awotwi ©Copyright Eminence Digital 2005 - 2010 All Right Reserved