How to create an empty dropdown list with default value? - asp.net-mvc

I want to create an empty dropdown list that has just default value.I use the following code:
#Html.DropDownList("parent","--Select Parent--")
But in running time I see this error:
There is no ViewData item of type 'IEnumerable' that
has the key 'parent'.
How can I solve it?
Thanks.

You can build an empty DropDownList like this:
#Html.DropDownList("parent", Enumerable.Empty<SelectListItem>(), "--Select Parent--")
Reference: Build an empty MVC DropdownListFor for a Cascade Sub-List

Adding html attributes to the above example:
#Html.DropDownList("Idparent", Enumerable.Empty<SelectListItem>(), "Select one...", new {#class="form-control"})

You may simply create an HTML Select option in your view.
<select id="parent" name="parent">
<option value="">Select parent </option>
</select>
EDIT : As per the comment.
When you submit the form, You can get the selected value by either having a parameter with parent name
[HttpPost]
public ActionResult Create(string parent,string otherParameterName)
{
//read and save and return / redirect
}
OR have a parent property in your ViewModel which you are using for Model binding.
public class CreateProject
{
public string parent { set;get;}
public string ProjectName { set;get;}
}
and in your action method.
[HttpPost]
public ActionResult Create(CreateProject model)
{
// check model.parent value.
}

You can do something like this in your controller to build a empty dropdown list
ViewBag.ClassID = new SelectList(db.Classes.Where(c => c.ClassID == 0) , "ClassID", "ClassName").ToList();

Related

kendo combobox send value to controller

I am trying to implement kendo ui combobox instead of normal dropdownlistfor. So, in my razor view, I replaced the code
#Html.DropDownList("clientid", (IEnumerable<SelectListItem>)clientList, "-- Select --", new { id="ddClients", name="ddClients"})
with
#(Html.Kendo().ComboBox()
.Name("ddClients")
.Filter("contains")
.Placeholder("-- Select --")
.DataTextField("Text")
.DataValueField("Value")
.BindTo((IEnumerable<SelectListItem>)clientList)
)
however in my controller
[HttpPost]
public ActionResult ClientDashboard(tblclient objClient, String submitButton)
{
...
}
I am not getting the client into tblclient object!
Please help.
Change your controller to this
[HttpPost]
public ActionResult ClientDashboard(int ddClients, String submitBUtton)
{
}
You can also bind the selected value directly to the view model.
For example:
Add the id to your model:
public Int32? ClientID {get; set;}
Add a hidden field to your view:
#Html.HiddenFor(x => x.ClientID)
Add a click event to assign the ClientID to the hidden field:
$("#submitButton").on("click", function () {
var combo = $("#ddClients").data("kendoComboBox");
$("#ClientID").val(combo.value());
});
Update: I just noticed that all you have to do is change the name of the combobox to ClientID and the value is bound to the view model without the hidden field and javascript.

MVC Model property resets on page submit

I'm new to MVC so this may sound silly, but here goes: I have a model that contains two lists that need to be passed to an edit form:
public class BaseViewModel
{
public IEnumerable<portal_notifications_types> Types { get; set; }
public IEnumerable<portal_notifications_importances> Importances { get; set; }
}
In the edit form, i Have two dropdownlists for this fields:
#Html.DropDownListFor(m => m.Notification.TypeId, new SelectList(Model.Types, "Id", "Type"), "-- Select type --", new { onchange = "GetNotifType();", style = "width:150px;" })
#Html.DropDownListFor(m => m.Notification.ImportanceId, new SelectList(Model.Importances, "Id", "Importance"), "-- Select importance --", new { style = "width:150px;" })
When I first enter the edit view, everything is ok, the dropdownlists are populated and the corresponding value is selected.
However, when I submit the form, the dropdownlists throw an error, because the Model.Types and Model.Importances lists are null.
How could I overcome this ? I would like to avoid using ViewBag to store those lists, although I know it would work.
Pass the View Model again in your Post Action Method.
[HttpPost]
public ActionResult Index(ViewModel m)
{
return View(m); //Pass the View Model again.
}
You have to repopulate these two SelectLists in the Controller POST method for Edit and again pass the ViewModel in the view for edit. Please share your Controller code for Edit for more details.

Creating DropDownListFor items in the view

I want to create a DropDownList with a binding for one of my model data, but i want the dropdown items to be built within the View and i do not want the items coming in the Model data or from my controller. Can you please suggest how to build the selectlist within View
Basically I want to create something like this:
<%= Html.DropDownListFor(model=>model.SomeProperty,<<create the dropdown list items here>> %>
Please suggest.
-Sampat.
You can't use it that way. As the name suggests its for returning an HTML select element for each property in the object that is represented by the specified expression using the specified list items and HTML attributes.
Though you can create this list object in view like following :-
#Html.DropDownListFor(model => model.DropDownElement,
new SelectList(model.DropDownElement, "Id", "Name"))
Update
I will take the example of a Country Model with an Id/Name pair. Like following
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
}
Now, in your controller action, you can pass it as a selectlist:
public ActionResult YourAction()
{
YourModel yourModel = new YourModel(); // Just for reference. I suppose you must be passing some model to your view
ViewBag.DropDownList = new SelectList(db.Countries, "Id", "Name"); // This way you don't need to make any changes with your passing model.
return View(yourModel);
}
And finally in View, you can use the DropDownListFor in the following manner.
#Html.DropDownListFor(model => model.YourModelProperty,
(IEnumerable<SelectListItem>)ViewBag.DropDownList, "---Select a value---")
On a Sidenote, if you just want to display a list of numbers with value, you can directly enter the HTML and utilize it, rather than using the DropDownListFor. Like follwing
<select id="yourModelPropertyName" name="yourModelPropertyName">
<option value="">---Select Value---</option>
<option value="1">India</option>
<option value="2">Australia</option>
<option value="3">US</option>
<option value="4">England</option>
<option value="5">Finland</option>
</select>
Just make sure that "yourModelPropertyName" is correct and it should be the one for the property where you want it updated
More update
In the views where you wan't to show the selected value, use below code
<select id="yourModelPropertyName" name="yourModelPropertyName">
<option selected="selected" value="1">#model.YourDropDownList</option>
<option value="2">India</option>
<option value="3">Australia</option>
</select>
This shall do the trick :-)
#Pankaj gave you a rough way of doing it. You can also pass the IEnumerable of SelectListItem object tobject to your view from controller and create your select element based on that.
Here is a good example:
A Way of Working with Html Select Element (AKA DropDownList) In ASP.NET MVC
Imagine that your controller looks like something like this:
public ActionResult Index() {
var products = productRepo.GetAll();
registerProductCategorySelectListViewBag();
return View(products);
}
private void registerProductCategorySelectListViewBag() {
ViewBag.ProductCategorySelectList =
productCategoryRepo.GetAll().Select(
c => new SelectListItem {
Text = c.CategoryName,
Value = c.CategoryId.ToString()
}
);
}
on your view, DropDownListFor html helper should look like something like this:
#Html.DropDownListFor(m => m.CategoryId,
(IEnumerable<SelectListItem>)ViewBag.ProductCategorySelectList
)

Invalid ModelState when moving items from one select list to another via javascript

I've got a page that contains two lists, one empty, one populated with values, both identical in structure. A user can select an item from the populated list, click a button, and it will move to the empty list via jQuery. When the form is submitted, I save all the option ids into a hidden form field to be later parsed out after post. However, when I submit the page, if I have moved a value from one listbox to the other, I encounter the following error (otherwise, the page posts normally):
System.InvalidOperationException: The parameter conversion from type
'System.String' to type 'System.Web.Mvc.SelectListItem' failed because no type
converter can convert between these types. at
System.Web.Mvc.ValueProviderResult.ConvertSimpleType(CultureInfo culture, Object value, Type destinationType) at
System.Web.Mvc.ValueProviderResult.UnwrapPossibleArrayType(CultureInfo culture, Object value, Type destinationType) at
System.Web.Mvc.ValueProviderResult.ConvertTo(Type type, CultureInfo culture) at
System.Web.Mvc.ValueProviderResult.ConvertTo(Type type) at
System.Web.Mvc.DefaultModelBinder.ConvertProviderResult(ModelStateDictionary modelState, String modelStateKey, ValueProviderResult valueProviderResult, Type destinationType)
Here is the relevant code:
ViewModel:
public class ViewModel
{
public IEnumerable<SelectListItem> currentUsers { get; set; }
public IEnumerable<SelectListItem> availableUsers { get; set; }
}
Initial Controller Action:
public ActionResult Index()
{
IEnumerable<User> availableUsers = SomeDal.GetUsers();
var model = new ViewModel
{
currentUsers = Enumerable.Empty<User>().Select(x => new SelectListItem
{
Value = x.id.ToString(),
Text = x.name
}),
availableUsers = availableUsers.Select(x => new SelectListItem
{
Value = x.id.ToString(),
Text = x.lastName
})
};
}
POST Controller Action:
[HttpPost]
public ActionResult Index(ViewModel model)
{
// at this point, ModelState.IsValid is already true, so I figure the rest of this isn't necessary
}
The jQuery that moves items:
$('#swapUsers').click(function () {
$('#availableUsers option:selected').appendTo('#currentUsers');
});
The ListBoxes::
#Html.ListBox(
"currentUsers",
new SelectList(Model.currentUsers, "value", "text"),
new { #class = "listbox" }
)
#Html.ListBox(
"availableUsers",
new SelectList(Model.availableUsers, "value", "text"),
new { #class = "listbox" }
)
I had thought at first it was because of my strange Enumerable.Empty call, but the error occurs even if the currentUsers IEnumerable contains data.
EDIT 1:
HTML Pre-Post
<select class="listbox" id="currentUsers" multiple="multiple" name="currentUsers"></select>
<select class="listbox" id="availableUsers" multiple="multiple" name="availableUsers">
<option value="1">Test User 1</option>
<option value="2">TestUser2</option>
</select>
HTML Post-Post
<select class="input-validation-error listbox" id="currentUsers" multiple="multiple" name="currentUsers">
<option selected="selected" value="1">Test User 1</option>
</select>
<select class="listbox" id="availableUsers" multiple="multiple" name="availableUsers">
<option value="2">TestUser2</option>
</select>
Keep in mind that the model that is getting posted to the server when the form is submitted will only include the list of selected values; You don't show/say, but it sounds like your action on submit is accepting the same ViewModel as the one you are using to display the form. The ViewModel class has IEnumerable for each of the properties, and the error you are getting is because the ModelBinder can't convert a list of strings to an IEnumerable<User> (or IEnumerable<SelectListItem>...A bit confused about that difference; Maybe your Model coming in (or parameters) to the method has an IEnumerable<SelectListItem>?).
Really, the form submission should have a model coming in that accepts the two lists (or actually it probably only needs the currentUsers list) as a list of integers (or whatever the actual type is).
public ActionResult PostMethod(IEnumerable<int> currentUsers)
{
...
}

DropDownListFor in EditorTemplate not selecting value

I have an editor template for a custom object. Inside that editor template I use a couple of DropDownListFor helpers. In each of them I specify a unique model property (with the pre-selected value) and the select list containing all the select options.
Example:
<%=Html.DropDownListFor(m => m.DocumentCategoryType, Model.DocumentCategoryTypeList) %>
I know that the option values are being populated (from viewing source) and that my Model is passed in with the correct ID value (DocumentCategoryType).
When the view is rendered, there is no selected item in my dropdown and therefore it defaults to the first (non-selected) value.
Does anyone have any ideas?
Thanks.
We also solved the solution by populating a new SelectList that has the appropriate SelectListItem selected, but created this extension method to keep the call to DropDownListFor a little cleaner:
public static SelectList MakeSelection(this SelectList list, object selection)
{
return new SelectList(list.Items, list.DataValueField, list.DataTextField, selection);
}
Then your DropDownListFor call becomes:
<%= Html.DropDownListFor(m => m.DocumentCategoryType, Model.DocumentCategoryTypeList.MakeSelection(Model.DocumentCategoryType)) %>
Looking through the ASP.NET MVC 2 source code reveals some solutions to this problem. Essentially, any SelectListItem in the SelectList passed in the helper extension method that has the Selected property set to true does not have any bearing over the <option> element rendered with the selected attribute applied for the item.
The selected attribute on <option> elements is determined by
1) checking that the helper extension method was passed a SelectList. If this is null, the framework will look in the ViewData for a value corresponding to the key that is the view model property for which you wish to render the drop down list for. If the value is a SelectList, this will be used to render the <select> including taking any selected values, so long as the model state for the model property is null.
2) If a SelectList has been passed in the helper extension method and the model state for the model property is null, the framework will look in the ViewData for a default value, using the model property name as the key. The value in view data is converted to a string and any items in the SelectList passed to the helper extension method that have a value (if no value is set, then the Text will be checked) that matches the default value will have the Selected property set to true which in turn will render an <option> with the attribute selected="selected".
Putting this together, there are two plausible options that I can see to have an option selected and use the strongly typed DropDownListFor:
Using the following view model
public class CategoriesViewModel
{
public string SelectedCategory { get; private set ; }
public ICollection<string> Categories { get; private set; }
public CategoriesViewModel(string selectedCategory, ICollection<string> categories)
{
SelectedCategory = selectedCategory;
Categories = categories;
}
}
Option 1
Set a value in the ViewData in the controller rendering your view keyed against the property name of the collection used to render the dropdown
the controller action
public class CategoriesController
{
[HttpGet]
public ViewResult Select()
{
/* some code that gets data from a datasource to populate the view model */
ICollection<string> categories = repository.getCategoriesForUser();
string selectedCategory = repository.getUsersSelectedCategory();
CategoriesViewModel model = new CategoriesViewModel(selectedCategory, categories);
this.ViewData["Categories"] = selectedCategory;
return View(model);
}
[HttpPost]
public ActionResult Select(CategoriesViewModel model)
{
/* some code that does something */
}
}
and in the strongly typed view
<%: Html.DropDownListFor(m => m.Categories, Model.Categories.Select(c => new SelectListItem { Text = c, Value = c }), new { #class = "my-css-class" }) %>
Option 2
Render the dropdown using the name of the property of the selected item(s)
the controller action
public class CategoriesController
{
[HttpGet]
public ViewResult Select()
{
/* some code that gets data from a datasource to populate the view model */
ICollection<string> categories = repository.getCategoriesForUser();
string selectedCategory = repository.getUsersSelectedCategory();
CategoriesViewModel model = new CategoriesViewModel(selectedCategory, categories);
return View(model);
}
[HttpPost]
public ActionResult Select(CategoriesViewModel model)
{
/* some code that does something */
}
}
and in the strongly typed view
<%: Html.DropDownListFor(m => m.SelectedCategory, Model.Categories.Select(c => new SelectListItem { Text = c, Value = c }), new { #class = "my-css-class" }) %>
It is confirmed as a bug # aspnet.codeplex.com
and only behaves like this for strongly typed views.
Workaround: populate your SelectList in the view code
like
<%= Html.DropDown("DocumentCategoryType", new SelectList(Model.Categories,"id","Name",Model.SelectedCategory")) =>
Yuck. I ended up solving it like this. I hope this gets fixed for RTM.
<%if(Model!=null){ %>
<%= Html.DropDownListFor(m => m.DocumentCategoryType, new SelectList(Model.DocumentCategoryTypeList,"Value","Text", Model.DocumentCategoryType))%>
<%}else{%>
<%=Html.DropDownListFor(m => m.DocumentCategoryType, Model.DocumentCategoryTypeList) %>
<%}%>
Make sure you have a value assigned to m.DocumentCategoryType when you send it to the view.
Generally this value will get reset when you do a post back so you just need to specify the value
when returning to your view.
When creating a drop down list you need to pass it two values. 1. This is where you will store the selected value 2. Is the actual List
Example
<%=Html.DropDownListFor(m => m.DocumentCategoryType, Model.DocumentCategoryTypeList) %>
I made the mistake of setting the select list item Selected value to True. This won't do anything. Instead just assign a value to m.DocumentCategoryType in your controller and this will actually do the selection for you.
Here's another good solution if the source for your drop down list is an IEnumerable instead of a SelectList:
public static SelectList MakeSelection(this IEnumerable<SelectListItem> list, object selection, string dataValueField = "Value", string dataTextField = "Text")
{
return new SelectList(list, dataValueField, dataTextField, selection);
}
Model.DocumentCategoryTypeList
This is probably your problem. On the SelectListItems, do you set the value to the .ToString() output?
var list = new List<SelectListItem>()
{
new SelectListItem()
{
Value = Category.Book.ToString(),
Text = "Book"
},
new SelectListItem()
{
Value = Category.BitsAndPieces.ToString(),
Text = "Bits And Pieces" },
new SelectListItem()
{
Value = Category.Envelope.ToString(),
Text = "Envelopes" }
};
Works for me after doing that. It just needs to be able to match the value from the object
I managed to solve the same problem by saying the folling:
new SelectList(sections.Select(s => new { Text = s.SectionName, Value = s.SectionID.ToString() }), "Value", "Text")
This trick is converting to the value to a string. I know this has been mentioned in previous answers but i find my solution a little cleaner :). Hope this helps.
Copied na pasted from my project:
<%= Html.DropDownListFor(m => m.Profession.Profession_id, new SelectList(Model.Professions, "Profession_id", "Profession_title"),"-- Profession --")%>
Model that is passed:
...
public Profession Profession { get; set; }
public IList<Profession> Professions { get; set; }
...
Html generated:
<select id="Profession_Profession_id" name="Profession.Profession_id">
<option value="">-- Profesion --</option>
<option value="4">Informatico</option>
<option selected="selected" value="5">Administracion</option>
</select>
Works for me. I have this on the form and the only disadvantage is that if model is not valid and I return the model back to the view I have to reload the list of Professions.
obj.Professions = ProfileService.GetProfessions();
return View(obj);
I also had this problem with a field ProgramName. Turns out we used ViewBag.ProgramName in the BaseController and Layout.cshtml, and this was for a different purpose. Since the value in ViewBag.ProgramName was not found in the dropdownlist, no value was selected even though the SelectListItem.Selected was true for one item in the list. We just changed the ViewBag to use a different key and the problem was resolved.
Here is a drop-in DropDownListFor replacement that varies only slightly from the original MVC source.
Example:
<%=Html.FixedDropDownListFor(m => m.DocumentCategoryType,
Model.DocumentCategoryTypeList) %>
I was worried about the performance of making so many copies of my selectList, so instead, I added the selectedvalue as a custom attribute, then used jquery to actually perform the item select:
#Html.DropDownListFor(item => item.AttendeeID, attendeeChoices, String.Empty, new { setselectedvalue = Model.AttendeeID })
........
jQuery("select[setselectedvalue]").each(function () { e = jQuery(this); e.val(e.attr("setselectedvalue")); });

Resources