This project is read-only.

Insert/Update/Delete Mouse Dragging Sorting List 

This control needs reference to both MVCControlToolkit.Controls.Core-x.x.x.js.and MVCControlToolkit.Controls.Items-x.x.x.js.

 jquery-ui or the jquery-ui-interactions.min.js file included in the distribution are needed to enable rows dragging and sorting with the mouse.

The SortableListFor helper uses Jquery UI Sortable to implement an Insert/Update/Delete Mouse dragging sorting list. However, when mouse dragging is disabled it can be used as a datagrid that is always either in display mode or in edit mode. One can use it, in place of the standard Datagrid, either when one needs a display only grid or when no changes tracking is needed (all controls may be equipped with changes tracking in the commercial version of the toolkit).

The SortableListFor helper is quite easy to use:

 

@Html.SortableListFor(m => m.SubTasks, "SubTasksToSort", "SubTasksToSortAddItem", 0.7f,
                                        htmlAttributesContainer: new Dictionary<string, object> { { "class", "SortableList" } }
                    )

 

 

The first argument is the list to act on, the second argument is the item template, the third is the item for inserting a new element (optional), and the fourth is the opacity used when dragging an item. Then, there are an optional bool parameter to enable mouse dragging based sorting (default is dragging enabled), and optional Html attributes.

The item template can contain a sortable list delete button do enable deletion of the item:

<div id='<%: Html.PrefixedId("InnerContainer") %>'>
@Html.TextBoxFor(m => m.Name, new Dictionary<string, object> { { "class", "ToDoDetailName" } }) @Html.ValidationMessageFor(m => m.Name, "*") 
@Html.TextBoxFor(m => m.WorkingDays, new Dictionary<string, object> {{"class", "ToDoDetailDuration"}}) @Html.ValidationMessageFor(m => m.WorkingDays, "*")
@Html.SortableListDeleteButton("Delete",  ManipulationButtonStyle.Link)
</div>

If the canSort parameter is set to true (its default) items can be reordered by dragging them with the mouse.

One can apply different Css classes to even and odd rows by specifying the itemCss and the altItemCss optional parameters as shown below:

 

                 <@Html.SortableListFor(convertedKeywords, 
                    _S.L<string>(
                        (x) => x.TypedTextBoxFor(m => m, watermarkCss:"watermark", overrideWatermark: "insert keyword").ToString()+
                                x.SortableListDeleteButton("Delete",  ManipulationButtonStyle.Link).ToString()
                    ), 
                    "KeywordInsert", 0.8f,
                    htmlAttributesContainer: new Dictionary<string, object> { { "class", "SortableList" } }, 
                    itemCss: "normalRow", altItemCss: "alternateRow")
                  

 

If the user either delete a row or move it to a different location the Css classes are re-computed on the client side for the new configuration. Please, notice the use of the in-line template. For an introduction to the use of templates, please see here.

The control is able to accept also items that are subclasses of the class T used in the List<T> passed as first argumentWhen the View 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.

if the enableMultipleInsert parameter is set to true(its default) the developer can allow multiple new items be inserted by adding a SortableListAddButtonFor button near the sortable list helper:

 

@Html.SortableListAddButtonFor(m => m.SubTasks, "Add New Item")

 

If old Microsoft validation is enabled, the enableMultipleInsert parameter is automatically set to false, and only one single item insertion can be enabled. 

In order to enable one single insertion, enableMultipleInsert  needs to be set to false, and one has to furnish a template for the insertion as shown below:

 

<div >

@Html.SortableListAddButton("Insert New", ManipulationButtonStyle.Link)

<span id='<%: Html.SortableListNewName() %>' style="visibility:hidden">
@Html.TextBoxFor(m => m.Name, new Dictionary<string, object> { { "class", "ToDoDetailName" } }) @: Html.ValidationMessageFor(m => m.Name, "*") 
@Html.TextBoxFor(m => m.WorkingDays, new Dictionary<string, object> {{"class", "ToDoDetailDuration"}}) @: Html.ValidationMessageFor(m => m.WorkingDays, "*")
@Html.SortableListDeleteButton("Delete",  ManipulationButtonStyle.Link)
</span>
</div>

The SortableListNewName helper defines an id to work as a target for the insertion button.

If both the template and the external add button are provided the choice of the insertion mode is left to the value of the enableMultipleInsert parameter. If enableMultipleInsert is set to false the external add button is not renedered, on the contrary if enableMultipleInsert is set to true the template for adding a new item will not be rendered.

If neither the insertion template nor the external add button are provided insertions will not be allowed. 

As a default Each Item is wrapped by a <li> tag, while the whole list is automatically embedded into an <ul> tag. However if CanSort is false, both <li> <ul> can be substituted by other tags, and the an header and a footer can be addet to the items as shown below:

 

                @Html.SortableListFor(m => m.Keywords1, 
                    _S.L<string>(
                        (x) =>"<td>" + x.TypedTextBoxFor(m => m, watermarkCss:"watermark", overrideWatermark: "insert keyword").ToString()+
                                x.SortableListDeleteButton("Delete",  ManipulationButtonStyle.Link).ToString()
                                + "</td>"
                    ),
                    canSort: false,
                    allItemsContainer: ExternalContainerType.table,
                    itemContainer: ExternalContainerType.tr,
                    itemCss: "normalRow", altItemCss: "alternateRow",
                    headerTemplate: _S.L<string>((x) => "<td>Keywords Header</td>"),
                    footerTemplate: _S.L<string>((x) => "<td>Keywords Footer</td>"))
                
                @Html.SortableListAddButtonFor(m => m.Keywords1, "Add New Item")

 

Multiple Templates

The SortableListFor supports also the use of multiple templates. To take advantage of this feature it is enough to pass an array of templates instead of a simple template:

 

@Html.SortableListFor(
    m => m.AllPersons,
    new object[]{
        _S.H<Employed>(
            @<text>
                @item.HiddenFor(m => m.Code)
                <div><h3>Employed</h3></div>
                <div>
                    @item.LabelFor(m => m.Name) 
                    @item.TypedEditDisplayFor(m => m.Name, simpleClick: true) 
                    @item.ValidationMessageFor(m => m.Name, "*")
                </div>
                <div>
                    @item.LabelFor(m => m.SurName) 
                    @item.TypedEditDisplayFor(m => m.SurName, simpleClick: true) 
                    @item.ValidationMessageFor(m => m.SurName, "*")
                </div>
                <div>
                    @item.LabelFor(m => m.Department) 
                    @item.TypedEditDisplayFor(m => m.Department, simpleClick: true) 
                    @item.ValidationMessageFor(m => m.Department, "*")
                </div>
            </text>),
            _S.H<Customer>(
            @<text>
                @item.HiddenFor(m => m.Code)
                <div><h3>Customer</h3></div>
                <div>
                    @item.LabelFor(m => m.Name) 
                    @item.TypedEditDisplayFor(m => m.Name, simpleClick: true) 
                    @item.ValidationMessageFor(m => m.Name, "*")
                </div>
                <div>
                    @item.LabelFor(m => m.SurName) 
                    @item.TypedEditDisplayFor(m => m.SurName, simpleClick: true) 
                    @item.ValidationMessageFor(m => m.SurName, "*")
                </div>
                <div>
                    @item.LabelFor(m => m.ContactId) 
                    @item.TypedEditDisplayFor(m => m.ContactId,
                        ChoiceListHelper.Create(
                            Person.ExtractEmployed(Model.AllPersons),
                            m => m.Code,
                                 m => m.SurName), simpleClick: true)
                    @item.ValidationMessageFor(m => m.ContactId, "*")
                </div>
            </text>)
    },
    templateSelector: l => l is Employed ? 0:1,
    htmlAttributesItems: new Dictionary<string, object> { { "class", "PersonListItem" } },
    itemContainer: ExternalContainerType.div,
    allItemsContainer: ExternalContainerType.div,   
    canSort: false)   

 

Then you have to supply also a function that selects the right template for each item of the list. It is passed through the parameter templateSelector. The function take an item as argument and returns an index in the array of all templates. In the example above the l => l is Employed ? 0:1 function selects the template with index 0 if the item is an instance of Employed, and the template with index 1 if the item is an instance of Customer.

All sortable helpers have also another optional parameter that is usefull to handle multiple templates: 

 

Func<int, IDictionary<string, object>> htmlAttributesSelector

 

It is a function that maps the index of the template of the current item being rendered to some html attributes. The returned attributes are inserted in the root of the item. When not null value the the result of this function overrides the attributes passed through the htmlAttributesItems parameter.

When adding a new element to the list we must specify the template to use for the ne item. We can do this by passing the the index of the template to the add button:

 

 @Html.SortableListAddButtonFor(m => m.AllPersons, "Add new Employed", templateIndex:0) 
 @Html.SortableListAddButtonFor(m => m.AllPersons, "Add new Customer", templateIndex: 1)

 

In the example above we used two AddButtons, one for creating a new Employed, and one to create a new Customer.

The full code of the example is contained in the HeterogeneousListEditing file in the download area.

Last edited Jun 22, 2014 at 11:48 AM by frankabbruzzese, version 29

Comments

No comments yet.