Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Simple Listbox Swapper(Non Javascript) in .Net MVC and maintaining MVC view-state as json in hidden field

0.00/5 (No votes)
29 Oct 2013 1  
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 and SelectedAssignedItems).  
  • At first request Initial Lists("AvailableList" and "SelectedList") are data-bound.   
  • On subsequent post requests, the "AvailableList" and "SelectedList" are first bound from currentAvailableList and currentAssignedList and then updated based on our selection in SelectedAvailableItems and SelectedAssignedItems.
  • The current view-state of the lists is maintained as json objects in two hidden fields (viz. currentAvailableList and currentAssignedList). 
  • The two buttons "Add >>" and "<< Remove" swap items between SelectedAvailableItems and SelectedAssignedItems.   

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 

History

  • 30-Oct-2013 Initial draft.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here