Update/Insert/Delete/ Sortable Templated Datagrid

My choice for implementing a general purpose DataGrid is to embed the Data into a wapper Tracker<T>  containing a bool Changed and two properties of the same type of the Data: Value and OldValue.

  1. When the Item is deleted Value is set to null but OldValue contains the old data to be deleted in the database. The change is signalled by setting Changed to true.
  2. When the Item is created Value is set to the newly created data, while OldValue is set to null. The change is signalled by setting Changed to true.
  3. When the item is modified  Value and  OldValue contain the two versions of the data item and the change is signalled by setting Changed to true. 

The introduction of the wrapper doesn't break the separation of concerns between the View Model and the View because the wrapper isn't needed because of a particular choice about How to render the data, but on the contrary it is needed to support the controller in reflecting the data changes in the database.

The DataGrid keeps The OldValue between consecutive posts. When the user finally decide to move the changes to the DB he can call the Confirm() method of the Tracker<T> that sets the OldValue to the same value of the Value and resets the Change bool. Calling Cancel() cancels the modifications by setting the Value equal to the OldValue, and resetting the Change bool.

The grid is able to accept also items that are subclasses of the class T used in the Tracker<T> (however all Tracker<T> in the collection must use the same class)When the grid is posted the Model Binder is able to reconstruct the original subclass. For an example, of how to edit a list of heterogeneous elements, please, see the HeterogeneousListEditing example in the download area.

This control needs reference to MVCControlToolkit.Controls.Core-x.x.x.js and MVCControlToolkit.Controls.Grid-x.x.x.js)

The user can edit several items, delete several items and insert several items before posting. The templated DataGrid supports both old Microsoft validation and unobtrusive validation, however when old Microsoft validation is enabled the user is allowed to insert just one row before posting. One insertion only mode can always be enforced by setting to false the optional argument enableMultipleInsert parameter whose default value is true.

The Datagrid does changes tracking, and store the old values of all fields in hidden fields automatically. If the items contain properties that are not used one can specify explicitely the fields to store through the optional parameter toTrack. The fiedls passed through the toTrack parameters maybe also complex objects or lists; in such a case they are serialized in javascript and stored. This information is extracted automatically from the column descriptions if one uses a ThemedDataGrid(see the example theme included in the binary distribution). 

The list of fields to be passed to the toTrack parameter can be build easily with the help of the FieldsToTrack class as shown below:

 

@Html.DataGridFor(m => m.ToDoList, ItemContainerType.tr,
   "ToDoEditItem", "ToDoDisplayItem", null, "ToDoInsertItem", "ToDoUndeleteItem",
    itemCss: "normalRow", altItemCss: "alternateRow",
    toTrack: new FieldsToTrack<ToDoItem>().
       Add(f => f.Code).Add(f => f.Name).Add(f => f.Description).Add(m => m.Important)
                                   .Add(f => f.ToDoRoles).Add(f => f.ToDoRole))
                                   

 

User can customize the DataGrid by providing :

  • A Partial View or a template to be used as overall container for the whole grid. This parameter is optional. When it is not provided the helper renders just all items without any html surrounding them(see the example grid included in the BinaryWithSimpleExamples file in the download area)
  • The type of container to be used for the items: div, span, tr, td, ....etc(HTML5 tags are also supported ). The type of Item container can be also decided dynamically by providing a function that returns it based on the current item and on the current item position. Obligatory.
  • A Partial View or a template to be used as Dsiplay View Item Template. Obligatory. 
  • A Partial View or a template to be used as Insert/Edit View Item Template. Optional; necessary only if editing is required.
  • A Partial View or a template to be used for the new row insertion item, when in Display mode(in Edit mode it uses the normal edit template). Optional; necessary only if insertion is required.
  • A Partial View or a template to be used  as template for deleted rows. Optional; if omitted deleted rows simply disappear. Typically it is provided to put and undelete button inside it.
  • A function that returns the separator to be used between items as a function of the current item, and of its position. Optional; necessary only if the separator is required.
  • By specifying in the itemCss and the altItemCss optional parameters two different Css classes to be applyed, respectively, to odd and even items. If the User either delete or add a new row the Css classes are re-computed on the client side for the new configuration. 

Input fields, or input control that may cause data to to be submitted are allowed only in the Edit View Item Template. If you for some reason need to use Input fields (for example a readonly checkbox) in the other templates please add them the disabled='disabled' attribute, so they will not be submitted.

Operations on the DataGrid are done with the help of customizable DataButtons that can be of type: Insert, Edit, DeleteCancel, ResetRow, and Undelete 

  • Insert Button. It make a new item appears in edit mode and it san be placed only in the template for the insertion of a new item as shown in the examples below
  • Edit Button. It can be inserted only in the template for the display mode and it causes the item goes in edit mode without any post.
  • Delete Button. It can be placed only in the template for the display mode and it causes the item be deleted.
  • Cancel Button. It can be placed only in the template for the edit mode and it causes all values in the item be reset to their initial values and the item to go in display mode. Here, initial values means the values before the item was changed the first time, since initial values are kept after cllient-server round trips because of the Tracker<T> wrapper.
  • Reset Row Button. It is similar to the Cancel Button, but the item remains in edit mode.
  • Undelete Button. It can be placed only in the template for deleted items, and causes th item be undeleted.

Validation Helpers showing validation errors for each item can be inserted on both the edit and display templates, however this might cause each error appear twice in the validation summary.

Below a simple example. For a complete example see here.

The overall Template for the Grid:

<table>
<tr>
<td colspan="4"> TO DO LIST</td>
</tr>
<tr>
<td><strong>Name</strong></td>
<td><strong>Description</strong></td>
<td>Edid</td>
<td>Delete</td>
</tr>
@(ViewData["Content"] as MvcHtmlString)
</table>

the ViewData["Content"] renders all grid items.

The Display Template:

<td class="editor-field">
     @Html.ValidationMessageFor(m => m.Name, "*") @Model.Name 
</td>
<td class="editor-field">
     @Html.ValidationMessageFor(m => m.Description, "*") @Model.Description 
</td>
<td class="editor-label">
     @Html.ImgDataButton(DataButtonType.Edit, "../../Content/small_pencil.gif", null)
</td>
<td class="editor-label">
     @Html.LinkDataButton(DataButtonType.Delete, "Delete Item", null) </td>

Please note the use of the DataButtons.

The Edit Template:

            
<td class="editor-field">
    @Html.ValidationMessageFor(m => m.Name, "*") @Html.TextBoxFor(m => m.Name)
</td>
<td class="editor-field">
    @Html.ValidationMessageFor(m => m.Description, "*") @: Html.TextBoxFor(m => m.Description) 
</td>
<td class="editor-label" colspan="2">
    @Html.HiddenFor(m => m.Code)
    @Html.DataButton(DataButtonType.Cancel, "Cancel Changes", null)
</td>

Please note the use of the DataButtons

The insert item template:

<td colspan="4">@Html.DataButton(DataButtonType.Insert, "Insert New To Do Item", null)</td>

 

Finally, how to insert the Grid in your View:

@Html.DataGridFor(m => m.ToDoList, ItemContainerType.tr, 
   "ToDoEditItem", "ToDoDisplayItem", "ToDoGrid", "ToDoInsertItem", "ToDoUndeleteItem",
    itemCss: "normalRow", altItemCss: "alternateRow")

There are parameters also for specifying the attributes of the edit and display containers, the separators and possibly to specify also the item container dynamically.

The Datagrid can be reset to its initial values if them have not been committed yet by using a reset manipulation button:
@Html.ManipulationButton(ManipulationButtonType.ResetGrid, "Reset", m => m.ToDoList, null, ManipulationButtonStyle.Button)
It is also possible to undelete a single row. To this end one can specify the optional deleted row template through the parameter deletedTemplateName: , and simply put in it an undelete Data Button.
This way the template will substitute any deleted row, allowing the user to "see" it and possibly to undelete it:
            <td class="editor-field" colspan="3">
               Deleted Item: @:Model.Name 
            </td>
            
            <td class="editor-label" >
                
                <%Html.DataButton(DataButtonType.Undelete, "Undelete Item", null)
            </td>

Last edited Jun 22, 2014 at 11:47 AM by frankabbruzzese, version 36

Comments

frankabbruzzese Jan 29, 2011 at 7:37 PM 
Sorry, I have not answered before, but while I receive notifications from other section of the codeplex site I never received a notification from the comment section(I have not understoo yet why), ...so I have seen your comment just today when I updated the documentation for the 0.8 release that will be available next moday 31th of January.
Actually there was a bug introduded by a last minute change of name to a variable. In the new version the bug has been removed. Anyway, I already added the example of deleted item template you asked in the documentation. It will be available also in the example code distributed with the binaries of the library nex monday.

platoon76 Dec 23, 2010 at 10:30 AM 
Thank you very much, it is a very useful control. I been trying to implement a delete item template but it doesn't work. Could you post an example of this template as well? Thanks again and merry Xmas ;)