Simple Listbox Swapper(Non Javascript) in .Net MVC and maintaining MVC view-state as json in hidden field
Simple Listbox Swapper in .Net MVC. And How to maintain view-state for MVC view as JSON in hidden field.
Introduction
This is a simple ListBox swapper which might be useful at times we need one. Also the control maintains the view-state of the Lists as JSON in hidden fields in the form. (Thus can be used as example for maintaining mvc page view-state as Json in hidden field.)

Background
I tried searching for quick to use ListBox swapper but couldn't find the .Net MVC specific one online. There are some of useful implementations available though (some of links below).
Also, some times we may want to avoid repeated database trips in binding the View controls (like when we just need to display validation message with original View. Or when we want to maintain the updated view-state until "Save" button is pressed.) We can maintain the view-state as Json in hidden field.
Using the code
-
The code uses simple
Html.ListBoxFor
helper to render the two lists to select from(viz.SelectedAvailableItems
andSelectedAssignedItems
). - At first request Initial Lists("
AvailableList
" and "SelectedList
") are data-bound. - On subsequent post requests, the "
AvailableList
" and "SelectedList
" are first bound fromcurrentAvailableList
andcurrentAssignedList
and then updated based on our selection inSelectedAvailableItems
andSelectedAssignedItems
. - The current view-state of the lists is maintained as json objects in two hidden fields (viz.
currentAvailableList
andcurrentAssignedList
). - The two buttons "Add >>" and "<< Remove" swap items between
SelectedAvailableItems
andSelectedAssignedItems
.
Here is how our model looks like:
public class ListSwapperModel
{
public string Message { get; set; }
public bool IsSuccess { get; set; }
public int Id { get; set; }
public string DisplayName { get; set; }
public string btnSubmit { get; set; }
/// <summary>
/// This is the List to which the Selection List for "Available" items is
/// bound in initial render of view
/// </summary>
public IList<SelectListItem> AvailableList { get; set; }
/// <summary>
/// The json view-state of Availablelist
/// </summary>
public string currentAvailableList { get; set; }
/// <summary>
/// List of selected Available items submitted for swap (Add)
/// </summary>
public IList<string> SelectedAvailableItems { get; set; }
/// <summary>
/// This is the List to which the Selection List for "Assigned" items is
/// bound in initial render of view
/// </summary>
public IList<SelectListItem> AssignedList { get; set; }
/// <summary>
/// The json view-state of AssignedList
/// </summary>
public string currentAssignedList { get; set; }
/// <summary>
/// The List of selected Assigned items submitted for swap (Remove)
/// </summary>
public IList<string> SelectedAssignedItems { get; set; }
}
In our controller here is how we initially data-bind the two lists.
public ActionResult Index()
{
ListSwapperModel model = new ListSwapperModel();
model.Message = "Welcome to ListSwapper Demo!";
var serializer = new JavaScriptSerializer();
model.AvailableList = getAllListFromDB(); //Get the Available list from Database
model.AssignedList = new List<SelectListItem>();//Here I'm initializing the assigned list to null
model.currentAvailableList = serializer.Serialize(model.AvailableList); //Save ViewState
model.currentAssignedList = serializer.Serialize(model.AssignedList); //Save ViewState
return View(model);
}
In our "HttpPost" action we simply load the view-state first and then update it based on our selection:-
[HttpPost]
public ActionResult Index(ListSwapperModel model)
{
var serializer = new JavaScriptSerializer();
//bind the list from ViewState
if(model.currentAvailableList!=null)
model.AvailableList= serializer.Deserialize<List<SelectListItem>>(model.currentAvailableList); //Load the ViewState here
//bind the list from ViewState
if(model.currentAssignedList!=null)
model.AssignedList = serializer.Deserialize<List<SelectListItem>>(model.currentAssignedList); //Load the ViewState here
try
{
switch (model.btnSubmit.ToUpper())
{
case ("ADD >>"):
{
//Update the AvailableList & Assigned list on the basis of our selection
if ((model.SelectedAvailableItems == null) || (model.SelectedAvailableItems.Count <= 0))
{
throw new Exception("No Items Selected in the Available List.");
}
else
{
foreach (string itm in model.SelectedAvailableItems)
{
var slctItm = model.AvailableList.FirstOrDefault(i => i.Value.Equals(itm));
model.AvailableList.Remove(slctItm);
model.AssignedList.Add(slctItm);
}
}
}
break;
case ("<< REMOVE"):
{
//Update the AvailableList & Assigned list on the basis of our selection
if ((model.SelectedAssignedItems == null) || (model.SelectedAssignedItems.Count <= 0))
{
throw new Exception("No Items Selected in the Assigned List.");
}
else
{
foreach (string str in model.SelectedAssignedItems)
{
var slctItm = model.AssignedList.FirstOrDefault(i => i.Value.Equals(str));
model.AssignedList.Remove(slctItm);
model.AvailableList.Add(slctItm);
}
}
}
break;
case ("SAVE"):
{
model.Message = "Save Item here!";
model.IsSuccess = true;
}
break;
default:
model.Message = "Un-Identified action!";
break;
}
}
catch (Exception exc1)
{
model.Message = "Sorry an error has occured! =>"+exc1.Message;
model.IsSuccess = false;
//Log & handle exception
}
//Updating ViewState
if (model.AssignedList != null)
model.currentAssignedList = serializer.Serialize(model.AssignedList);
else
model.currentAssignedList = null;
if (model.AvailableList != null)
model.currentAvailableList = serializer.Serialize(model.AvailableList);
else
model.currentAvailableList = null;
//Updating ViewState
return View(model);
}
Our view is pretty much simple form with the two selection lists, two buttons ("Add >>" and "<< Remove") and the two hidden fields for view-states of our Available and Assigned lists.
<% using (Html.BeginForm())
{%>
<%= Html.ValidationSummary(true)%>
<table>
<tr><th>Display Name:</th><td><%= Html.TextBoxFor(m => m.DisplayName)%></td></tr>
<tr><td colspan="2">
<table class="tblNoBorders">
<tr><td>
<input type="hidden" id="currentAvailableList" name="currentAvailableList" value='<%= Model.currentAvailableList %>' />
<%= Html.ListBoxFor(m => m.SelectedAvailableItems, new SelectList(Model.AvailableList, "Value", "Text"), new { @class = "listswapper-list", @title = "Hold Ctrl/Command and left-click to deselect" })%>
</td>
<td><input type="submit" name="btnSubmit" style="width:80px;text-align:center;padding:0;" value="Add >>" /><br /><br />
<input type="submit" name="btnSubmit" style="width:80px;text-align:center;padding:0;" value="<< Remove" />
</td>
<td>
<input type="hidden" id="currentAssignedList" name="currentAssignedList" value='<%= Model.currentAssignedList %>' />
<%= Html.ListBoxFor(m => m.SelectedAssignedItems, new SelectList(Model.AssignedList, "Value", "Text"), new { @class = "listswapper-list", @title = "Hold Ctrl/Command and left-click to deselect" })%>
</td>
</tr>
</table>
</td></tr>
<tr><td colspan="2" style="text-align:right"><input type="submit" value="Save" name="btnSubmit" /></td></tr>
</table>
<%} %>
Points of Interest
- http://stackoverflow.com/questions/7248686/2-listboxes-exchange-items-in-mvc3
- http://cstruter.com/blog/115
- http://www.xploredotnet.com/2008/03/move-item-between-listbox.html
History
-
30-Oct-2013 Initial draft.