binding dropdown list in MVC - asp.net-mvc

Hi I am trying to Bind my dropdown list in MVC from a model.
Here is my model
[Table("FileConfig")]
public class FileConfigModel
{
[Key]
[Display(Name = "File Congif ID")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int FileConfigId { get; set; }
....
[Display(Name = "Description")]
public string Description { get; set; }
}
Here is my getall method in the controller:
public List<FileConfigModel> GetAll()
{
return db.FileConfigModels.ToList();
}
Then I am calling it from my another controller
public ActionResult Create()
{
var fileConfigListEntries = new FileConfigController().GetAll()
.Select(fc => new SelectListItem
{
Value = fc.FileConfigId.ToString(),
Text = fc.Description,
Selected = false
});
ViewBag.FileConfigEntires = fileConfigListEntries;
return View();
}
And here is my view:
#Html.LabelFor(model => model.FileConfigId, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.FileConfigId, ViewBag.FileConfigEntires as SelectList, "-Select File Config")
#Html.ValidationMessageFor(model => model.FileConfigId)
</div>
However, I've been keep getting error saying
"There is no ViewData item of type 'IEnumerable' that has the key 'FileConfigId'.."
Could someone please help me and tell me what I've missed.

Your query for fileConfigListEntries (i.e. ..Select(fc => new SelectListItem{ .. }) returns IEnumerable<SelectListItem>
In the view, you then try and convert that to typeof SelectList using ViewBag.FileConfigEntires as SelectList
SelectList is IEnumerable<SelectListItem>, but IEnumerable<SelectListItem> is not SelectList, therefore the conversion fails, and the 2nd parameter of DropDownListFor() is null. When the 2nd parameter is null, the method expects the 1st parameter to be IEnumerable<SelectListItem> which it is not, hence the exception.
Change your code to
#Html.DropDownListFor(m => m.FileConfigId, ViewBag.FileConfigEntires as IEnumerable<SelectListItem>, ... )
or
#Html.DropDownListFor(model => model.FileConfigId, (IEnumerable<SelectListItem>)ViewBag.FileConfigEntires, ... )
Side note There is no point setting Selected = false in the .Select clause - its false by default, but in any case, its ignored when binding to a model property (its the value of the property which determines what is selected)

Possible reason of above error could be variable fileConfigListEntries is null or not got the data from dbcontext.
As drop down list is bounded with null or collection with no elements error coming as "There is no ViewData item of type 'IEnumerable' that has the key 'FileConfigId'.."
I suggest replace fileConfigListEntries view bag data with hard-coded data and see error disappears.

Related

Set The selected Value of a Multiselect from Controller to View after submitting an invalid Model

I am using a Multiselect DropDownList to generate a multiple <select>
I was able to generate it and was working fine.
But If I try to submit it using the parameters:
Name = null
ObjAOption = [1,2] // assume I selected 2 options in my multiselect
ObjAOption will just select option value='1' instead of select options 1, and 2.
Is there any way I can get back the selected options and pass it back to my view by setting it in my controller? I would love to use HTML helper and not to use jQuery or javascript on this part.
Controller:
public ActionResult AddObjectA(AddModel am){
if(ModelState.IsValid){
//Save
}
else {
am.ObjA = // new List of ObjectA with atleast 4 option
return View("MyView",am);
}
}
View:
#Html.LabelFor(model => model.ObjA, "Object A")
#Html.DropDownList("ObjAOption", new MultiSelectList(Model.ObjA, "Key", "Name"), "-- Select Object A--", new { #class = "custom-select custom-select-sm", multiple="" })
#Html.ValidationMessageFor(m => m.ObjAOption, "", new { #class = "text-danger" })
Model:
public class AddModel {
[Required]
public String Name {get;set;}
public IEnumerable<ObjectA> ObjA{ get; set; }
[Required(ErrorMessage = "Please select at least one option")]
public List<int>ObjAOption{ get; set; }
}
public class ObjectA {
public int Key {get;set;}
public string Name {get;set;}
}
Have you tried to use the helper Hiddenfor ? It generate a field that keep your element value, name and attribute :
View:
#Html.LabelFor(model => model.ObjA, "Object A")
#Html.DropDownList("ObjAOption", new MultiSelectList(Model.ObjA, "Key", "Name"), "-- Select Object A--", new { #class = "custom-select custom-select-sm", multiple="" })
#Html.ValidationMessageFor(m => m.ObjAOption, "", new { #class = "text-danger" })
#Html.HiddenFor(m => m.ObjAOption)
Solution:
I scrapped out my DropDownList and tried using ListBoxFor as discussed here

Select default value for DropDownListFor using ViewBag as SelectList

In my controller I have a list of Agents stored in ViewBag
ViewBag.Agents = new SelectList(db.Users.ToList(), "Id", "UserName", string.Empty);
In my View I have display this as a DropDownListFor
#Html.DropDownListFor(model => a.AgentList, ViewBag.Agents as SelectList, new { #class = "form -control", #style = "width:130px; height:30px" })
However, my list is not showing the already selected Agent as Default. What am I missing? How can I set the Dropdownlist to display selected Agent as default?
I even tried this but nothing work:
#Html.DropDownListFor(model => a.AgentList, new SelectList( ViewBag.Agents as SelectList, a.AgentName), new { #class = "form -control", #style = "width:130px; height:30px" })
Here is my model
[Display(Name = "Agent ID")]
public string AgentID { get; set; }
[Display(Name = "Agent Name")]
public string AgentName { get; set; }
[Display(Name = "Agent")]
public List<ApplicationUser> AgentList { get; set; }
Thank you for helping
Please use the below step for bind the selected value in DropDownListFor.
Step:- 1 ViewBag.Agents= db.Users.ToList();
Step:- 2 #Html.DropDownListFor(model => Model.AgentID, new SelectList(ViewBag.Agents, "Id", "UserName",2))
Try:
#Html.DropDownListFor(model => a.AgentList, new SelectList( ViewBag.Agents, Model.AgentName), new { #class = "form -control", #style = "width:130px; height:30px" })
Hi you make use of this overload of selectlist
SelectList Constructor (IEnumerable, String, String, Object)
public SelectList(
IEnumerable items,
string dataValueField,
string dataTextField,
object selectedValue
)
It will initializes a new instance of the SelectList class by using the specified items for the list, the data value field, the data text field, and a selected value.
So you code will change like:
ViewBag.Agents = new SelectList(db.Users.ToList(), "Id", "UserName", 10 /*Default user Id*/);
What I have found, is that if the form is bound to a Model, the model value (which is probably null by default) will override whatever selected value is set by the ViewBag List. So, it is best to set the default value inside the model.
For example:
[ViewModel for the form] ModelFormType ViewModel = new ModelFormType();
ModelFormType.UserId = 11 (default user Id).

Issue with Model Binding

I have created a View Model called CompetitionRoundModel which is partially produced below:
public class CompetitionRoundModel
{
public IEnumerable<SelectListItem> CategoryValues
{
get
{
return Enumerable
.Range(0, Categories.Count())
.Select(x => new SelectListItem
{
Value = Categories.ElementAt(x).Id.ToString(),
Text = Categories.ElementAt(x).Name
});
}
}
[Display(Name = "Category")]
public int CategoryId { get; set; }
public IEnumerable<Category> Categories { get; set; }
// Other parameters
}
I have structured the model this way because I need to populate a dropdown based on the value stored in CategoryValues. So for my view I have:
#using (Html.BeginForm())
{
<div class="form-group">
#Html.LabelFor(model => model.CategoryId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.CategoryId, Model.CategoryValues, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.CategoryId, "", new { #class = "text-danger" })
</div>
</div>
// Other code goes here
}
I have selected model.CategoryId in the DropDownListFor() method since I want to bind the selected value to CategoryId. I really don't care for CategoryValues, I just need it to populate the DropDown.
My problem now is that when my Controller receives the values for my Model in the action method, CategoryValues is null which causes the system to throw a ArgumentNullException (the line that is highlighted is the return Enumerable line.
I have even tried [Bind(Exclude="CategoryValues")] but no change at all. Any help would be much appreciated.
Your not (and should not be) creating form controls for each property of each Category in your IEnumerable<Category> collection so in your POST method, the value of Categories is null (it never gets initialized). As soon as you attempt CategoryValues and exception is thrown by your .Range(0, Categories.Count()) line of code in the getter.
Change you view model to give CategoryValues a simple geter/setter, and delete the Categories property
public class CompetitionRoundModel
{
public IEnumerable<SelectListItem> CategoryValues { get; set; }
[Display(Name = "Category")]
public int CategoryId { get; set; }
.... // Other properties
}
and populate the SelectList in the controller methods, for example
var categories db.Categories; // your database call
CompetitionRoundModel model = new CompetitionRoundModel()
{
CategoryValues = categories.Select(x => new SelectListItem()
{
Value = x.Id.ToString(),
Text = x.Name
},
....
};
return View(model);
or alternatively
CompetitionRoundModel model = new CompetitionRoundModel()
{
CategoryValues = new SelectList(categories, "Id", "Name" ),
Note also that if you return the view (because ModelState is invalid, the you need to repopulate the value of CategoryValues (refer The ViewData item that has the key 'XXX' is of type 'System.Int32' but must be of type 'IEnumerable' for more detail)
Since CategoryValues just populates the drop down, it will never post back to the server and you'll need to rebuild the list from the database before using it in the GET or POST operation. The CategoryId property is the value that will be posted back to the server from the DropDownList.

DropDownList cant get selected values

I'm stucked at creating dropdownlist in ASP.NET MVC.
ViewModel:
public MultiSelectList users { get; set; }
I set the values in controller:
var allUsers = db.Users.Select(u => new {
id = u.UserId,
name = u.Name
}).ToList();
model.users = new MultiSelectList(allUsers, "id", "name");
so selectbox values are set.
In view:
#Html.DropDownListFor(m => m.users, Model.users, new { #class = "form-control" })
The problem is that if I select the value and click submit i get this error:
No parameterless constructor defined for this object.
I think the problem is in the way how I create the dropdownlist in view, I'm not sure how to set it, thanks.
EDIT: If I dont choose any user from dropdown all goes well, but if I choose then the error appears.
You're trying to post to the MultiSelectList property. That's not going to work regardless, but the specific error is related to the fact that MultiSelectList has no parameterless constructor, and there's no way for the modelbinder to new up a class with parameters. Anything involved in the modelbinding process must have a parameterless constructor.
What you should be doing is have an additional property like:
public List<int> SelectedUserIds { get; set; }
And, then bind to that in your view:
#Html.ListBoxFor(m => m.SelectedUserIds, Model.Users)
Also, as you'll notice, I changed DropDownListFor to ListBoxFor. If you're wanting to have a select multiple, you need ListBoxFor.
Looks like it is failing when trying to bind, so to prevent it from binding:
[HttpPost]
public ActionResult YourMethod([Binding(Exclude = "users")] SomeViewModel model)
The post back should go to an IEnumerable to capture the selected items.
Add to view model
public IEnumerable UserList { get; set; }
Change view to
#Html.DropDownListFor(m => m.UserList, Model.users, new { #class = "form-control" })
If you want get selected user id from a dropdownlist you must add a property to your model
public MultiSelectList users { get; set; }
public int SelectedUser { get;set;}
And in view
#Html.DropDownListFor(m => m.SelectedUser, Model.users, new { #class = "form-control" })

MVC MultiSelectList Binding

I use ASP.NET MVC .. When i post my form it's raise cast error when my model validate. How can fixed my view model or another validation way?
"The parameter conversion from type 'System.String' to type 'System.Web.Mvc.SelectListItem' failed because no type converter can convert between these types."
Thank you..
//my view model
public class ProdGroupViewModel
{
//I've to fixed here or another way?
public IEnumerable<SelectListItem> Rooms { get; set; }
}
//controller
public ActionResult Create(int id)
{
return View(new ProdGroupViewModel
{
Rooms = new MultiSelectList(_roomService.GetAll(), "RoomId", "RoomName"),
});
}
//in my view
<div class="form-group">
<label class="col-md-3 control-label">Oda</label>
<div class="col-md-9">
#Html.ListBoxFor(model => model.Rooms, (MultiSelectList)Model.Rooms, new { #class = "form-control" })
</div>
</div>
You're trying to post to the same property that holds your select list. The posted result of a selections in a listbox will be a comma-delimited string of the selected option values, which the modelbinder would be incapable of binding to a property of type MultiSelectList.
You need an additional model property to hold the posted value like:
public List<int> SelectedRoomIds { get; set; }
And then in your view:
#Html.ListBoxFor(m => m.SelectedRoomIds, Model.Rooms, new { #class = "form-control" })
Also, you don't need to cast Model.Rooms, since it's already strongly-typed.

Resources