The Select2 javascript plugin gives you a customizable select box with support for searching, tagging, remote data sets, infinite scrolling, and many other. It gives a wonderful user experience when you integrate with a web application. In this example, I will show you how to implement a multi-select control with an MVC application. The multiselect control allows a user to select more than one item in a listbox or in a selectlist. The aim of this tutorial is to allow a user to select multiple values from a select list then store the selected values into the database table. I have tried to make this in very simple way. Retrieve the data and fetch them in a listbox control with the selected items or values. The end result will be like this –
STEP ONE
Create a movie model to interact with the database using object-relational mapping.
public class Movie { public int ID { get; set; } [StringLength(60, MinimumLength = 3)] public string Title { get; set; } // [Display(Name = "Release Date"), DataType(DataType.Date)] //cover everything in one line [Display(Name = "Release Date")] [DataType(DataType.Date)] [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)] public DateTime ReleaseDate { get; set; } [RegularExpression(@"^[A-Z]+[a-zA-Z''-'\s]*$")] [Required] [StringLength(30)] public string Genre { get; set; } [Range(1, 100)] [DataType(DataType.Currency)] public decimal Price { get; set; } [Display(Name ="Description")] [AllowHtml] public string Description { get; set; } [RegularExpression(@"^[A-Z]+[a-zA-Z''-'\s]*$")] [StringLength(5)] public string Rating { get; set; } public byte[] BarcodeImage { get; set; } public string Barcode { get; set; } public string ImageUrl { get; set; } //string field to store the selected values public string CategoryVal { get; set; } //list of selected categories ids public IEnumerable<int> SelectedCat { get; set; } //populate the list of categories from the categories public IEnumerable<Category> categories { get; set; } }
STEP TWO
Now, let me explain the model attributes. The CategoryVal is a database table column to store the selected items from the list. SelectedCat is an IEnumerable object to hold the array of selected items. In the controller, Convert the int arrays into a comma-separated string and set the SelectedCat value to this string on form post. I am just showing here the record edit scenario but it will be the same for adding a new record. Here is the ActionResult method of the MovieController –
// GET: Movies/Edit/5 public ActionResult Edit(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } Movie movie = db.Movies.Find(id); //convert string to List and bind with multiselect if(movie.CategoryVal!=null) { List<int> sl = movie.CategoryVal.Split(',').Select(Int32.Parse).ToList(); movie.SelectedCat = sl; } //get the movie categories and bind with the model object movie.categories = db.Categories.ToList(); if (movie == null) { return HttpNotFound(); } return View(movie); }
In the above HTTP Get method, setting the category multiselect value from the database. I have used a if condition so that it will not fetch the selected value if the column is empty or returns a null value. Convert the CategoryVal string into an array of int then set the multiselect value field. This field accepts the
You can see the categories value has been stored as a string in the database table.
Edit view cshtml file contains the following code –
@{ ViewBag.Title = "Edit"; } <h2>Edit</h2> @using (Html.BeginForm()) { @Html.AntiForgeryToken() <div class="form-horizontal"> <h4>Movie</h4> <hr /> @Html.ValidationSummary(true, "", new { @class = "text-danger" }) @Html.HiddenFor(model => model.ID) <div class="form-group"> @Html.LabelFor(model => model.Title, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Title, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Title, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.ReleaseDate, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.ReleaseDate, "{0:dd/MM/yyyy}", new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.ReleaseDate, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Genre, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Genre, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Genre, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Description, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @* @Html.EditorFor(model => model.Description, new { htmlAttributes = new { @class = "form-control" } }) *@ @Html.TextArea("Description", null, new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.Description, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Price, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Price, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Price, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Rating, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Rating, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Rating) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Barcode, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Barcode, new { htmlAttributes = new { @class = "form-control" } }) <img src="~/Movies/ShowPhoto/@Model.ID" /> @Html.ValidationMessageFor(model => model.Barcode) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Category, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.ListBoxFor(m => m.SelectedCat, new MultiSelectList(Model.categories, "CategoryID", "CategortyName", Model.SelectedCat), new { @class = "chosen-select form-control", multiple = "multiple" }) </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> @Html.ActionLink("Back to List", "Index", null, null, new { @class = "btn btn-default" }) <input type="submit" value="Save" class="btn btn-primary" /> </div> </div> </div> } <div> </div> @section Scripts { @Scripts.Render("~/bundles/jqueryval") <link href="~/Scripts/chosen/prism.css" rel="stylesheet" /> <link href="~/Scripts/chosen/chosen.min.css" rel="stylesheet" /> <script src="~/Scripts/chosen/chosen.jquery.min.js"></script> <script src="~/Scripts/chosen/prism.js"></script> <script type="text/javascript"> $(function () { $(".chosen-select").chosen({ disable_search_threshold: 10, no_results_text: "Oops, nothing found!"//, // width: "45%" }); }); </script> }
[attention title=”Important Note”]Make sure you include the jQuery library and Select2 js and css files. Bind them on dom ready. [/attention]
STEP THREE
When the form is submitted, capture the array from the multiselect list and convert them to a string before binding on the model object. Here is the HTTP post Action method.
[HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit([Bind(Include = "ID,Title,ReleaseDate,Genre,Price,Rating, Description,CategoryVal,BarCode,BarcodeImage,SelectedCat")] Movie movie) { var cat = db.Categories.ToList(); if (ModelState.IsValid) { //set the barcode barcode objbar = new barcode(); byte[] img = objbar.getBarcodeImage(objbar.generateBarcode(), movie.Title); movie.Barcode = objbar.generateBarcode(); movie.BarcodeImage = img; //join the array and convert to string to save in the database string scat = string.Join(",", movie.SelectedCat); movie.CategoryVal = scat; db.Entry(movie).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(movie); }
Please note, above code block contains a middleware object reference for the barcode generation. I am not explaining this here since it is out of the scope of this tutorial.
Here is the end result once you implement this in a very simple way.
Very good article for me. If possible please master details operation in ASP .Net MVC application like sale bill with order and order item detail.
Thanks for this. my problem now is how to display the string values of categoryVal field in my view page. i get the ids instead of the actual text selected at my view page. please help me out. thanks
Could you show the ‘Create’ action method too for adding new Movie???
Hi,
The create action is pretty simple since it selected movies field is using string. You just use as simple model property to bind the variables.