What Functionality do we need?
Looking at the control they had produced, I was able to identify the following items of functionality that I needed to create to complete my challenge:
- Add sorting functionality.
- Add inline editing functionality.
- Add paging functionality.
- Add functionality to add/delete elements.
Populating the table
To make it simple at this stage, I decided to have a single column of data containing ten numbers and then build on that later to add more complex data and columns. The population was relatively simple, as shown in Listing A (Demo1 in the accompanying download).
Demonstration files available for download
Now that I had the data in the table, the next thing I wanted to do was to add sorting functionality. I based this code on my recent article on the same topic. The resulting Demo2 can be seen in the download—a more complex example can be found on my Web site.
To amend the content, I needed to be able to uniquely identify each row and each cell in my table so that I could update their contents. To do this, I added a <DIV> within every cell that I could reference because each would be given a unique ID attribute. This was done very simply by modifying one line of code as shown Listing B.
Next, I needed to add an Edit button for each Row, to do this I decided to add a new column before the data column to hold the "Action" buttons. This was achieved by adding the code shown in Listing C.
To keep the table in the correct shape, I also needed to add a header cell in the table for my newly created column.
I now had a method of identifying each individual row in my table, and an action button for it. My next challenge was creating the code to do the edit itself. Breaking down the required functionality into its components, I ended up with the following steps:
- Identify the Row chosen.
- Get the current value of the Cell in that Row.
- Update the content of the Cell to include a textbox for editing and a Save and Cancel button.
- Once the Save button is pressed, save the updated value and redisplay the table.
- If the Cancel button is pressed, reset the table to its normal state.
The first item is provided as the parameter to the editRow function called when the button is pressed. The second can be derived either from the Cell itself, or from the Array—as the Row number is also the Array index value. The third uses the getElementById and innerHTML methods to update the content of the specified DIV. The final two steps are very similar to the second and third steps; I need to grab the new value from the textbox and then convert the Cell back to a normal Cell with the new value.
To support the inline editing functionality, I needed to create three distinct new functions:
- An Edit function to convert the Cell to Edit mode
- A Save function to save the changes and update the table
- A Cancel function to quit Edit mode and redisplay the table
The Edit function was relatively simple; all it needed to do was to get hold of the cell and update its content with the textbox and the Save and Cancel buttons. The Save function simply got the new value and assigned it to the correct place in the array, and then repopulated the table. The Cancel function simply repopulated the table.
To ensure that only a single row can be edited at a time, some code was added to the Edit function to check to see if the Currently In Edit Mode flag was set, and if so, cancel that change and then restart the new one. Code to clear the flag was also added to the Save and Cancel functions. Combining all this together I ended up with Demo3.
Nearing the finishing line, my next challenge was to add the Paging functionality to the code. For this to work, we need to know two things, which record is the current one and how many items to display per page. To make the implementation of this slightly easier, I am going to take this in three stages:
- Basic paging
- Basic paging with Sorting
- Basic paging with Sorting and Inline Editing
For the basic paging, we also require two new functions, one to move forward a page and one to move back a page. For the paging, we need to change the loop in the function that creates the cells that form the table's content to loop between the start and end points rather than the entire dataset. After building the content of the table, we also need to add navigation links to allow the user to move backwards or forwards through the data as appropriate. This simple paging approach can be seen in Demo4.
When moving forwards or backwards through a page of data we need to be careful of going over the bounds of the dataset. For example if we have a page size of three elements, then our pages will show elements 1-3,4-6,7-9,10-12. However, as our sample dataset only has 10 elements, when we hit the fourth page, we will get an error as the code is unable to locate elements 11 and 12 of our dataset. To resolve this, we simply add an if statement into the loop that builds the table content to ensure that there is an element to display. A similar issue faces us if we moving back through the data, but this can be handled by ensuring that the value of our start location is always a positive integer or zero, and if negative, changing it to zero.
When looking at sorting within a given page, we have several options as to what to display when the sort has completed. We could just sort the elements on the given page, we could sort the entire dataset and show the same page in the newly sorted dataset, or we could go back to the first page of the dataset and allow the user to navigate through again.
I decided on the latter of these options as it seems the most sensible option of the three. To achieve this, we simply need to take our sorting example Demo2 code and add a line of code to reset the start index back to zero once the sort has completed. This ensures that the first page displayed of the sorted data is the first n elements of the dataset. The example code for this can be found in Demo5.
The final step is to add the inline editing to this code; this is a simple merger of the previously created inline editing code and the paging and sorting code we have just created. No additional code or changes are required for this to work. An example of inline editing and paging is available in Demo6.
The final challenge was to add functionality to allow me to delete an existing element or add a new element to the dataset. Starting with the Delete option, all we need to do is to shuffle all the elements of our dataset up one after the deleted element and then delete the last element, as shown Table A.
The code for adding and deleting elements will be tied to an extra button that is displayed in Edit mode for a given row. The code for this functionality can be seen in Demo7.
That just leaves the Add row functionality, to achieve this we will add an extra row to the table, then redisplay the DataGrid with that newly created cell in Edit mode. When creating the extra element in the array, we need to give it a value; to ensure that it appears last, we will give it a value of null. However, the null appears as plain text in the appropriate place in our grid when its row is in both Normal and Edit modes. Thus, we need to make a few small changes to the code that generates the table—to replace it with a space when displayed in Normal mode to keep the structure of the Table or with an empty string when in Edit mode. Putting all of the code together results in the Demo8 file.
Some possible extensions to this functionality include the following:
- Managing multiple columns
- Adding event handlers to check data entry, for example, numeric only, SSN, ISBN, etc.
- Loading and Saving data
- Provide specific sort routines for different datatypes
- Add page numbers to allow the user to jump to specific pages rather than moving though each in turn
- Make some of the functionality, such as sorting and paging, optional