I got two ways to bind my list of values to a dropdown in MVC3. But not sure which is the difference and the best/simpler way to bind.
//Code
public List<SelectListItem> CountryList
{
get
{
return new List<SelectListItem>
{
new SelectListItem { Value = "1", Text = "Bangladesh" },
new SelectListItem { Value = "2", Text = "India" },
new SelectListItem { Value = "3", Text = "Nepal" },
new SelectListItem { Value = "4", Text = "SriLanka" },
};
}
}
(Or)
public SelectList StatusList()
{
List<SelectListItem> lstStatus = new List<SelectListItem>
{
new SelectListItem { Value = "1", Text = "Yes" },
new SelectListItem { Value = "2", Text = "No" },
};
return new SelectList(lstStatus, "Value", "Text", Status);
}
Do i have any advantages/disadvantages in one over another. I have to bind these values and get/set the selected value. Which method will be best one go with?
Kindly suggest.
I tend to use a generic enumeration of SelectListItem in MVC applications. The main reason is that makes more sense when you use ViewModels with your views.
Let's say I have movies stored in a database. I represent a movie with a POCO class.
public class Movie
{
public string Genre { get; set; }
}
The page to edit the movie receive a ViewModel.
public class MovieViewModel
{
public string Genre { get; set; }
public IEnumerable<SelectListItem> GenreList
{
get
{
yield return new SelectListItem { Text = "Comedy", Value = "1" };
yield return new SelectListItem { Text = "Drama", Value = "2" };
yield return new SelectListItem { Text = "Documentary", Value = "3" };
}
}
}
The ViewModel is my model but with additional properties to personalize my view, like the list of the available genres.
Finally in my view, I populate my dropdownlist using the ASP.NET wrapper Html.DropDownListFor().
#model MvcApplication1.Models.MovieViewModel
<!DOCTYPE html>
<html>
<head>
<title>Index</title>
</head>
<body>
<div>
#Html.DropDownListFor(m => m.Genre, Model.GenreList)
</div>
</body>
</html>
The selected value is then automatically chosen using the ViewModel.
Related
I have this model:
public class CampoTipoDocumentoViewModel
{
public int TipoDocumentoId { get; set; }
public string[] CamposId { get; set; }
private List<MiddleTier.Models.ICampo> _todosCampos;
public IEnumerable<SelectListItem> TodosCampos
{
get
{
foreach (var campo in _todosCampos)
yield return new SelectListItem { Text = campo.Nombre, Value = campo.Id.ToString() };
}
}
public void SetFields(List<MiddleTier.Models.ICampo> campos)
{
_todosCampos = campos;
}
}
In controller, CamposId property is assigned with elements which has to be selected in the view.
Controller also calls SetFields method populating _todosCampos to the whole list of records in the system.
The idea is to create a View with a SELECT that has initially some records selected.
This is my view:
#Html.DropDownListFor(m => m.CamposId, Model.TodosCampos, new { #class = "form-control", multiple = "multiple", width = "100%" })
The fact is that the HTML SELECT element is created with the list, but no option is selected.
For example, if _todosCampos contains:
Text = "One", Value = "1"
Text = "Two", Value = "2"
Text = "Three", Value = "3"
Text = "Four", Value = "4"
and CamposId contains:
Array of "2", "4"
I need the view to create a SELECT with those 4 options, and option 2 and 4 to be initially selected.
How can I achieve this?
Thanks
Jaime
In order to use <select> element with multiple="multiple" attribute, you need to declare List<string> property:
public List<string> CamposId { get; set; }
And then use ListBoxFor helper instead of DropDownListFor:
#Html.ListBoxFor(m => m.CamposId, Model.TodosCampos, new { #class = "form-control", multiple = "multiple", width = "100%" })
If you want to set some option values are selected by default, then set Selected property into SelectListItem:
public IEnumerable<SelectListItem> TodosCampos
{
get
{
foreach (var campo in _todosCampos)
{
// assumed you have 'campo.IsDefault' which is boolean property
yield return new SelectListItem
{
Text = campo.Nombre,
Value = campo.Id.ToString(),
Selected = campo.IsDefault // set default selected values
};
}
}
}
Note: Usually ID property contain integer values, you can try for List<int> CamposId depending on actual ID data type in database.
I have issue with correct bind SelectListItem with a view.
ItemController.cs
public ActionResult SelectCondition()
{
List<SelectListItem> items = new List<SelectListItem>();
items.Add(new SelectListItem { Text = "New", Value = "0", Selected=true });
items.Add(new SelectListItem { Text = "Old", Value = "1" });
var model = new Item
{
ItemCondition = items
};
return View();
}
Create.cshtml
#Html.DropDownList("SelectCondition", (IEnumerable<SelectListItem>)Model.ItemCondition)
Item.cs
public IEnumerable<SelectListItem> ItemCondition { get; set; }
Now I have NullReferenceException and underlined this line in Create.cshtml
Isn't it very suspicious for Visual Studio that var model is declared but never used?
Pass the model to the view. return View(model).
And general suggestion: Work with strongly typed views...
I am trying to create a drop down list but it gives me an error saying 'Cannot implicitly convert type 'string' to 'System.Web.Mvc.SelectList'. My code is below:
Application Database Model:
public string dropdown{ get; set; }
Application View Model:
public SelectList dropdown{ get; set; }
ApplicationService.cs:
public static SelectList GetDropdownList(string currSelection)
{
List<SelectListItem> list = new List<SelectListItem>();
list.Add(new SelectListItem { Value = "1", Text = "firstvalue" });
list.Add(new SelectListItem { Value = "2", Text = "secondvalure" });
list.Add(new SelectListItem { Value = "3", Text = "All of the Above" });
return new SelectList(list, "Value", "Text", currSelection);
}
in my controller i am calling:
applicationviewmodel.dropdown= ApplicationService.GetDropdownList(null);
and then trying to save it in database as:
ApplicationDatabaseModel.dropdown= applicationviewmodel.dropdown;
This is where i get this error.
In my view i have:
#Html.DropDownListFor(x => x.dropdown, applicationviewmodel.dropdown)
I am not sure how to make this work.
I find it's easier to just have a List as part of your model and use a simple linq statement. Simple example below for a countries drop down:
assuming you have a model like
public class MyModel()
{
public int CountryId { get; set; }
public List<Country> Countries { get; set; }
}
and a Country class of
public class Country()
{
public int Id { get; set; }
public string Name { get; set; }
}
in your view you can then do the following:
#Html.DropDownListFor(m => m.CountryId,
Model.Countries.Select(x =>
new SelectListItem { Text = x.Name, Value = x.Id.ToString(), Selected = Model.CountryId == x.Id }, "Please Select...", null)
This:
#Html.DropDownListFor(x => x.dropdown, applicationviewmodel.dropdown)
..is incorrect. It is trying to store the selected item into the SelectList instance.
What you want is a string variable on the view model that this value is selected into:
public class ApplicationViewModel {
public SelectList DropDown { get; set; }
public string SelectedDropDownValue { get; set; }
// .. the rest of the properties here
}
Then your view becomes this:
#Html.DropDownListFor(x => x.SelectedDropDownValue, Model.DropDown)
This says "store the selected value into SelectedDropDownValue".
Then, you need to change how you build your SelectList. Value is what gets posted to your property.. Text is what is displayed in the browser.
So this:
list.Add(new SelectListItem { Value = "1", Text = "firstvalue" });
list.Add(new SelectListItem { Value = "2", Text = "secondvalure" });
list.Add(new SelectListItem { Value = "3", Text = "All of the Above" });
..has to be this:
list.Add(new SelectListItem { Value = "firstvalue", Text = "firstvalue" });
list.Add(new SelectListItem { Value = "secondvalue", Text = "secondvalure" });
list.Add(new SelectListItem { Value = "all of the above", Text = "All of the Above" });
..because they are strings (unless of course, you want the numbers to be posted back).
Then, finally, your controller code becomes this:
// assign the string value to the string property
ApplicationDatabaseModel.dropdown = applicationviewmodel.SelectedDropDownValue;
#Html.DropDownListFor(m => m.branch, CommonMethod.getBranch("",Model.branch), "--Select--", new { #multiple = "multiple" })
#Html.DropDownListFor(m => m.division, CommonMethod.getDivision(Model.branch,Model.division), "--Select--", new { #multiple = "multiple" })
I have two instances of DropDownListFor. I want to set selected as true for those which have previously stored values for Model.branch and Model.division. These are string arrays of stored ids
class CommonMethod
{
public static List<SelectListItem> getDivision(string [] branchid , string [] selected)
{
DBEntities db = new DBEntities();
List<SelectListItem> division = new List<SelectListItem>();
foreach (var b in branchid)
{
var bid = Convert.ToByte(b);
var div = (from d in db.Divisions where d.BranchID == bid select d).ToList();
foreach (var d in div)
{
division.Add(new SelectListItem { Selected = selected.Contains(d.DivisionID.ToString()), Text = d.Description, Value = d.DivisionID.ToString() });
}
}
}
return division;
}
}
The returned value of division is selected as true for the selected item in the model, but on view side it is not selected.
Use a ListBoxFor instead of DropDownListFor:
#Html.ListBoxFor(m => m.branch, CommonMethod.getBranch("", Model.branch), "--Select--")
#Html.ListBoxFor(m => m.division, CommonMethod.getDivision(Model.branch, Model.division), "--Select--")
The branch and division properties must obviously be collections that will contain the selected values.
And a full example of the proper way to build a multiple select dropdown using a view model:
public class MyViewModel
{
public int[] SelectedValues { get; set; }
public IEnumerable<SelectListItem> Values { get; set; }
}
that would be populated in the controller:
public ActionResult Index()
{
var model = new MyViewModel();
// preselect items with values 2 and 4
model.SelectedValues = new[] { 2, 4 };
// the list of available values
model.Values = new[]
{
new SelectListItem { Value = "1", Text = "item 1" },
new SelectListItem { Value = "2", Text = "item 2" },
new SelectListItem { Value = "3", Text = "item 3" },
new SelectListItem { Value = "4", Text = "item 4" },
};
return View(model);
}
and in the view:
#model MyViewModel
...
#Html.ListBoxFor(x => x.SelectedValues, Model.Values)
It is the HTML helper that will automatically preselect the items whose values match those of the SelectedValues property.
For me it works also for #Html.DropDownListFor:
Model:
public class MyViewModel
{
public int[] SelectedValues { get; set; }
public IEnumerable<SelectListItem> Values { get; set; }
}
Controller:
public ActionResult Index()
{
var model = new MyViewModel();
// the list of available values
model.Values = new[]
{
new SelectListItem { Value = "2", Text = "2", Selected = true },
new SelectListItem { Value = "3", Text = "3", Selected = true },
new SelectListItem { Value = "6", Text = "6", Selected = true }
};
return View(model);
}
Razor:
#Html.DropDownListFor(m => m.SelectedValues, Model.Values, new { multiple = "true" })
Submitted SelectedValues in controller looks like:
Though quite old thread but posting this answer after following other answers here, which unfortunately didn't work for me. So, for those who might have stumbled here recently or in near future, Below is what has worked for me.
This is what helped me
The catch for me was MultiSelectList class and I was using SelectList.
Don't know situation in 2012 or 2015. but, now both these helper methods #Html.DropDownListFor and #Html.ListBoxFor helper methods accept IEnumerable<SelectListItem> so you can not pass any random IEnumerable object and expect these helper methods to do the job.
These helper methods now also accept the object of SelectList and MultiSelectList classes in which you can pass the selected values directly while creating there objects.
For example see below code how i created my multi select drop down list.
#Html.DropDownListFor(model => #Model.arrSelectUsers, new MultiSelectList(Model.ListofUsersDTO, "Value", "Text", #Model.arrSelectUsers),
new
{
id = "_ddlUserList",
#class = "form-control multiselect-dropdown",
multiple = "true",
data_placeholder = "Select Users"
})
So I have a area setup (Admin). In the Admin Area I have a _ViewStart.cshtml file which links to a Shared/_Layout.cshtml file.
What I need is for the layout file to get some data passed to it (like a model). There will be a drop down at the top right of the page which is common accross all pages in the admin area. It wouldn't be used in any other areas or the root of the application, only in this area.
Is there a way to assign a common controller to a layout or is Partial the way forward with this?
You could use child actions. You could define a model:
public class MyViewModel
{
public string SelectedId { get; set; }
public IEnumerable<SelectListItem> Items { get; set; }
}
then have a controller:
public class ItemsController: Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
Items = new[]
{
new SelectListItem { Value = "1", Text = "item 1" },
new SelectListItem { Value = "2", Text = "item 2" },
new SelectListItem { Value = "3", Text = "item 3" },
}
};
return PartialView(model);
}
}
and then a corresponding partial (~/Areas/Admins/Views/Items/Index.cshtml):
#model MyViewModel
#Html.DropDownListFor(x => x.SelectedId, Model.Items)
Now, inside the layout of your are you could render this action:
#Html.Action("Index", "Items", new { area = "admin" })