In my MVC application, I am retrieving a list of objects based on an ID and stuffing those objects into a Listbox via a SelectList. Here is what I have:
C#
ViewBag.SpecCatListBox = new SelectList(SelectListMethods.LstChosenSpecCat(incidentVm.ID), "Value", "Text");
HTML/Razor
#Html.ListBoxFor(model => model.LstSpecialCategories, (SelectList)ViewBag.SpecCatListBox, new { id = "SpecialCat-ListBox", #class = "form-control" })
On page load, the listbox is filled with the correct options, except that they're not selected. Is there a way to do this without looping (which is what I've seen in other posts)?
Any help is appreciated.
UPDATE
I've edited a few things, along with added a line of code.
C#
ViewBag.SpecCatListBox = new SelectList(SelectListMethods.LstChosenSpecCat(incidentVm.ID), "Value", "Text", SelectListMethods.LstChosenSpecCat(incidentVm.ID));
ViewBag.SpecCatIds = db.TBL_AssocIncidentSpecialCat.Where(x => x.IncidentId == incidentVm.ID)
.Select(x => x.SpecialCategoriesId).ToList();
HTML/Razor
#Html.ListBoxFor(model => model.LstSpecialCategories, new MultiSelectList(ViewBag.SpecCatListBox, "Value", "Text", ViewBag.SpecCatIds), new { id = "SpecialCat-ListBox", #class = "form-control" })
This is selecting all of the options as needed, but is there a way to not use 2 Viewbag objects?
I have figured this out.
C#
ViewBag.SpecCatListBox = new MultiSelectList(SelectListMethods.LstChosenSpecCat(incidentVm.ID), "Value", "Text", SelectListMethods.LstChosenSpecCat(incidentVm.ID).Select(x => x.Value));
HTML/Razor
#Html.ListBoxFor(model => model.LstSpecialCategories, (MultiSelectList)ViewBag.SpecCatListBox, new { id = "SpecialCat-ListBox", #class = "form-control" })
Related
I'm trying to get this datepicker field to populate with today's date but it's not happening for some reason. I can't find a reference for what options are accepted in the "new {}" section.
#Html.LabelFor(d => d.ServiceOn, new { #class = "control-label" })
#Html.EditorFor(d => d.ServiceOn, "DatePicker", new { disableMinDate = true, Value = DateTime.Today })
#Html.ValidationMessageFor(d => d.ServiceOn, "", new { #class = "text-danger" })
I've tried value, Value and #Value but the resulting html always shows value="". I'm wondering if maybe the datepicker itself is zeroing out the field. I feel like I'm missing something obvious here.
This should work:
#Html.LabelFor(d => d.ServiceOn, new { #class = "control-label" })
#{Model.ServiceOn= DateTime.Today;}
#Html.EditorFor(d => d.ServiceOn, "DatePicker", new { disableMinDate = true })
#Html.ValidationMessageFor(d => d.ServiceOn, "", new { #class = "text-danger" })
HTML work with the ModelState, not from the model itself.
If you want more loose helpers, ise #Html.Editor instead.
I have a form with a MultiSelectList and I'm using .Net validation to require a selection be made amongst required other vields. When I submit, the multiple selections are sent to the controller correctly but if requirements aren't met, ModelState is invalid, I return back to the form. I'm using the below line to set the ViewBag instance of the MultiSelectList with the selections that were made. The code seems to work. However, the view only displays a single selection, the first selection, not any of the others that were sent and returned.
ViewBag.SelectedServiceLines = new MultiSelectList(db.LookUps.Where(lu => lu.RecordType == "ServLine"), "ID", "Description", funder.SelectedServiceLines.Select(i => i));
If I step through the razor code in my view I can view the ViewData and see that there is a MultiSelectList and it does have all of the selections that were sent to the controller and then returned. But only one of those selections are displayed. Below is how I'm displaying the list. I can't figure out why only one item is being displayed and not the multiple that get sent back and are in the ViewBag as "SelectedItems" for the MultiSelectList.
#Html.DropDownList("SelectedBusinessLines", null, htmlAttributes: new { #class = "form-control chosen-select", #multiple = "multiple" })
You can use either MultiSelectList or IEnumerable<SelectListItem>, depending on your choice:
// MultiSelectList approach
ViewBag.SelectedServiceLines = new MultiSelectList(db.LookUps.Where(lu => lu.RecordType == "ServLine"), "ID", "Description", funder.SelectedServiceLines.ToList());
// IEnumerable<SelectListItem> approach
ViewBag.SelectedServiceLines = db.LookUps.Where(lu => lu.RecordType == "ServLine")
.Select(i => new SelectListItem() {
Text = i.Description,
Value = i.Id,
Selected = funder.SelectedServiceLines.Contains(i.Id)
}).ToList();
Then use ListBox[For] helper instead of DropDownList[For] to create <select> element with multiple attribute:
#* MultiSelectList approach *#
#Html.ListBoxFor(model => model.SelectedBusinessLines, ViewBag.SelectedServiceLines as MultiSelectList, new { #class = "form-control chosen-select", #multiple = "multiple" })
#* IEnumerable<SelectListItem> approach *#
#Html.ListBoxFor(model => model.SelectedBusinessLines, ViewBag.SelectedServiceLines as IEnumerable<SelectListItem>, new { #class = "form-control chosen-select", #multiple = "multiple" })
Note that the ViewBag properties have dynamic type, you need to cast into respective type to avoid view rendering problem.
Side note
You may try create a MultiSelectList or IEnumerable<SelectListItem> property inside viewmodel:
public MultiSelectList SelectedServiceLines { get; set; }
And populate it with same way as ViewBag mentioned above:
var model = new ViewModel(); // use your viewmodel class name
model.SelectedServiceLines = new MultiSelectList(db.LookUps.Where(lu => lu.RecordType == "ServLine"), "ID", "Description", funder.SelectedServiceLines.ToList());
return View(model);
Then use it with ListBoxFor helper, but this time without any cast unlike ViewBag does:
#Html.ListBoxFor(model => model.SelectedBusinessLines, Model.SelectedServiceLines, new { #class = "form-control chosen-select", #multiple = "multiple" })
Can you try this instead? I've always used a List<SelectListItem> instead of a MultiSelectList:
// Use List<SelectListItem> instead
ViewBag.SelectedServiceLines =
db.LookUps
.Where(lu => lu.RecordType == "ServLine")
.Select(i => new SelectListItem() { Text = i.Description, Value = i.Id })
.ToList();
I also suggest using a ListBox instead:
#Html.ListBox("SelectedBusinessLines", ViewBag.SelectedBusinessLines, htmlAttributes: new { #class = "form-control chosen-select", #multiple = "multiple" })
As the question says:
How to set selectedValue in DropDownListFor Html helper?
Tried most of the other solutions but none worked that's why I am opening a new question.
Nothing of these helped:
#Html.DropDownListFor(m => m.TipPopustaId, new SelectList(Model.TipoviDepozita, "Id", "Naziv", 2), htmlAttributes: new { #class = "form-control" })
//Not working with or without cast
#Html.DropDownListFor(m => m.TipPopustaId, new SelectList(Model.TipoviDepozita, "Id", "Naziv", (ProjectName.Models.TipDepozita)Model.TipoviDepozita.Single(x => x.Id == 2)), htmlAttributes: new { #class = "form-control" })
#Html.DropDownListFor(m => m.TipPopustaId, new SelectList(Model.TipoviDepozita, "Id", "Naziv", (ProjectName.Models.TipDepozita)Model.TipoviDepozita.Where(x => x.Id == 2).FirstOrDefault()), htmlAttributes: new { #class = "form-control" })
#Html.DropDownListFor(m => m.TipPopustaId, new SelectList(Model.TipoviDepozita, "Id", "Naziv", new SelectListItem() { Value="2", Selected=true}), htmlAttributes: new { #class = "form-control" })
I would like to avoid manual creation of SelectListItems or a ViewModel just for the list if possible.
When you use the DropDownListFor() (or DropDownList()) method to bind to a model property, its the value of the property that sets the selected option.
Internally, the methods generate their own IEnumerable<SelectListItem> and set the Selected property based on the value of the property, and therefore setting the Selected property in your code is ignored. The only time its respected is when you do not bind to a model property, for example using
#Html.DropDownList("NotAModelProperty", new SelectList(Model.TipoviDepozita, "Id", "Naziv", 2))
Note your can inspect the source code, in particular the SelectInternal() and GetSelectListWithDefaultValue() methods to see how it works in detail.
To display the selected option when the view is first rendered, set the value of the property in the GET method before you pass the model to the view
I also recommend your view model contains a property IEnumerable<SelectListItem> TipoviDepozita and that you generate the SelectList in the controller
var model = new YourModel()
{
TipoviDepozita = new SelectList(yourCollection, "Id", "Naziv"),
TipPopustaId = 2 // set the selected option
}
return View(model);
so the view becomes
#Html.DropDownListFor(m => m.TipPopustaId, Model.TipoviDepozita, new { #class = "form-control" })
Make Sure that your return Selection Value is a String and not and int when you declare it in your model.
Example:
public class MyModel
{
public string TipPopustaId { get; set; }
}
public static class EnumHelper
{
public static SelectList EnumToSelectList<TEnum>(this Type enumType, object selectedValue)
{
return new SelectList(Enum.GetValues(enumType).Cast<TEnum>().ToList().ToDictionary(n=> n), "Key", "Value", selectedValue);
}
}
And in your View:
#Html.DropDownListFor(model => model.Role, EnumHelper.EnumToSelectList<Role>(typeof(Role), Model.Role), new { htmlAttributes = new { #class = "padding_right" } })
#Html.ValidationMessageFor(model => model.Role, "", new { #class = "text-danger" })
Instead of EnumToList use any Other List and select Key and Value of your Listtype Properties
I noticed there is no razor oriented approach, i added below
var prices = from P in Model[idx].prices.Values
where !P.Key.ToLower().Contains("san")
select new SelectListItem()
{
Text = P.Key + " Month " + (Convert.ToDecimal(P.Value) + ((Convert.ToDecimal(P.Value) / 100) * 20)).ToString("0.##") + " $",
Value = P.Key
};
prices.ToList()[0].Selected = true;
#Html.DropDownListFor(model => prices.ToList()[0], prices)
Just going to add my preferred way of doing this is to render the select statement myself as it gives greater control over the HTML, rather than using the Razor control.
<select class="form-control" id="my-id">
#foreach (var item in Model.ListOfItems) {
var selected = "";
if (item.Value == "whatever") {
selected = "selected='selected'";
}
<option #selected value="#item.Value">#item.Text</option>
}
</select>
As the question says:
How to set selectedValue in DropDownListFor Html helper?
Tried most of the other solutions but none worked that's why I am opening a new question.
Nothing of these helped:
#Html.DropDownListFor(m => m.TipPopustaId, new SelectList(Model.TipoviDepozita, "Id", "Naziv", 2), htmlAttributes: new { #class = "form-control" })
//Not working with or without cast
#Html.DropDownListFor(m => m.TipPopustaId, new SelectList(Model.TipoviDepozita, "Id", "Naziv", (ProjectName.Models.TipDepozita)Model.TipoviDepozita.Single(x => x.Id == 2)), htmlAttributes: new { #class = "form-control" })
#Html.DropDownListFor(m => m.TipPopustaId, new SelectList(Model.TipoviDepozita, "Id", "Naziv", (ProjectName.Models.TipDepozita)Model.TipoviDepozita.Where(x => x.Id == 2).FirstOrDefault()), htmlAttributes: new { #class = "form-control" })
#Html.DropDownListFor(m => m.TipPopustaId, new SelectList(Model.TipoviDepozita, "Id", "Naziv", new SelectListItem() { Value="2", Selected=true}), htmlAttributes: new { #class = "form-control" })
I would like to avoid manual creation of SelectListItems or a ViewModel just for the list if possible.
When you use the DropDownListFor() (or DropDownList()) method to bind to a model property, its the value of the property that sets the selected option.
Internally, the methods generate their own IEnumerable<SelectListItem> and set the Selected property based on the value of the property, and therefore setting the Selected property in your code is ignored. The only time its respected is when you do not bind to a model property, for example using
#Html.DropDownList("NotAModelProperty", new SelectList(Model.TipoviDepozita, "Id", "Naziv", 2))
Note your can inspect the source code, in particular the SelectInternal() and GetSelectListWithDefaultValue() methods to see how it works in detail.
To display the selected option when the view is first rendered, set the value of the property in the GET method before you pass the model to the view
I also recommend your view model contains a property IEnumerable<SelectListItem> TipoviDepozita and that you generate the SelectList in the controller
var model = new YourModel()
{
TipoviDepozita = new SelectList(yourCollection, "Id", "Naziv"),
TipPopustaId = 2 // set the selected option
}
return View(model);
so the view becomes
#Html.DropDownListFor(m => m.TipPopustaId, Model.TipoviDepozita, new { #class = "form-control" })
Make Sure that your return Selection Value is a String and not and int when you declare it in your model.
Example:
public class MyModel
{
public string TipPopustaId { get; set; }
}
public static class EnumHelper
{
public static SelectList EnumToSelectList<TEnum>(this Type enumType, object selectedValue)
{
return new SelectList(Enum.GetValues(enumType).Cast<TEnum>().ToList().ToDictionary(n=> n), "Key", "Value", selectedValue);
}
}
And in your View:
#Html.DropDownListFor(model => model.Role, EnumHelper.EnumToSelectList<Role>(typeof(Role), Model.Role), new { htmlAttributes = new { #class = "padding_right" } })
#Html.ValidationMessageFor(model => model.Role, "", new { #class = "text-danger" })
Instead of EnumToList use any Other List and select Key and Value of your Listtype Properties
I noticed there is no razor oriented approach, i added below
var prices = from P in Model[idx].prices.Values
where !P.Key.ToLower().Contains("san")
select new SelectListItem()
{
Text = P.Key + " Month " + (Convert.ToDecimal(P.Value) + ((Convert.ToDecimal(P.Value) / 100) * 20)).ToString("0.##") + " $",
Value = P.Key
};
prices.ToList()[0].Selected = true;
#Html.DropDownListFor(model => prices.ToList()[0], prices)
Just going to add my preferred way of doing this is to render the select statement myself as it gives greater control over the HTML, rather than using the Razor control.
<select class="form-control" id="my-id">
#foreach (var item in Model.ListOfItems) {
var selected = "";
if (item.Value == "whatever") {
selected = "selected='selected'";
}
<option #selected value="#item.Value">#item.Text</option>
}
</select>
How do I update my textboxes to display the Email1 and Mobile1 properties of my Contact model based on the selected value in a dropdownlist
View
#Html.LabelFor(model => model.CustomerName , new { #class = "control-label" })
#Html.DropDownListFor(model => model.CustomerContactID, new SelectList(string.Empty, "Value", "Text"), "Please select a ContactPerson", new { #style = "width:250px;" })
#Html.LabelFor(model => model.Email1, new { #class = "control-label" })
#Html.TextBoxFor(model => model.ContactID, new { #class = "form-control", type = "text" })
#Html.ValidationMessageFor(model => model.Email1)
#Html.LabelFor(model => model.MobileNo1, new { #class = "control-label" })
#Html.TextBoxFor(model => model.ContactID, new { #class = "form-control", type = "text" })
#Html.ValidationMessageFor(model => model.MobileNo1)
Script
$('#CustomerContactID').change(function () {
$('#ContactID').empty();
$.ajax({
type: "GET",
url: "/VisitorsForm/GetEmailByCustomerContactId",
datatype: "Json",
data: { CustomerContactID: $('#CustomerContactID').val() },
success: function (data) {
$('#Email1').val(data.Email1);
$('#MobileNo1').val(data.Mobile1);
}
});
});
Controller
public JsonResult GetEmailByCustomerContactId(string CustomerContactId)
{
Guid Id = Guid.Parse(CustomerContactId);
var contacts = from a in db.Contacts where a.ContactID == Id select a;
return Json(contacts);
}
Your query in the GetEmailByCustomerContactId() returns IEnumerable<Contact>, a collection, not a single object, so data in the ajax success call back is an array and $('#Email1').val(data.Email1); fails because an array does not have a property named Email1 (but each item in the collection does)
Since you only want to return one Contact, change your query to
var contact = (from a in db.Contacts where a.ContactID == Id select a).FirstOrDefault();
and since you only want 2 properties of Contact, then return an anonymous object containing only those properties (there is no point degrading performance by sending data across the wire which you never use
var data = new { Email1 = contact.Email1, Mobile1 = contact.Mobile1 };
and finally specify the JsonRequestBehavior option since your making a GET call
return Json(data, JsonRequestBehavior.AllowGet;);
Next, your not generating any inputs with id="Email1" and id="Mobile1". Both textboxes you have create bind to ContactID, so I assume these should be
#Html.TextBoxFor(model => model.Email1, new { #class = "form-control" })
#Html.TextBoxFor(model => model.Mobile1, new { #class = "form-control" })
assuming that Email1 and Mobile1 are also properties of the model in the view.
Your textboxes will now be updated in the success callback
Side notes:
Always use url: '#Url.Action(....)', to ensure the correct url is
generated
Use data: { CustomerContactID: $(this).val() },
Change your method parameter to public JsonResult
GetEmailByCustomerContactId(Guid CustomerContactId) and delete the
Guid.Parse (the DefaultModelBinder will do the conversion)
Remove new { type = "text" } from your Html.TextBoxFor() methods
(the helper already adds that)