We have a plain ASP.NET MVC form with lots of fields. The first field is the most important, and it's a dropdown list. Let's say it's the pany field and it contains two value "Coca Cola" and "Pepsi".
The pany field looks like this:
<div class="editor-label">
@Html.LabelFor(Function(model) model.Company)
</div>
<div class="editor-field">
@Html.DropDownListFor(Function(model) model.Company, TryCast(ViewData("Companies"), SelectList), New With {Key .style = "blah blah;"})
@Html.ValidationMessageFor(Function(model) model.Company)
</div>
Because it's important this choice is actively made and is not simply left on "Coca Cola" simply because it's first alphabetically, we need the field to be empty first of all (validation data annotations take care of forcing the user to put something in).
This is easily done with Javascript like so:
function InitialiseForm() {
$('#Company').prop('selectedIndex', -1);
}
window.onload = InitialiseForm;
However, we have a few cases where the form isn't loaded entirely blank, and instead the pany field is initialised in the controller, like so:
modelObject.Company = "Coca Cola"
and in such cases we of course don't want the Javascript to execute and erase this.
What's the normal solution in such cases?
We have a plain ASP.NET MVC form with lots of fields. The first field is the most important, and it's a dropdown list. Let's say it's the pany field and it contains two value "Coca Cola" and "Pepsi".
The pany field looks like this:
<div class="editor-label">
@Html.LabelFor(Function(model) model.Company)
</div>
<div class="editor-field">
@Html.DropDownListFor(Function(model) model.Company, TryCast(ViewData("Companies"), SelectList), New With {Key .style = "blah blah;"})
@Html.ValidationMessageFor(Function(model) model.Company)
</div>
Because it's important this choice is actively made and is not simply left on "Coca Cola" simply because it's first alphabetically, we need the field to be empty first of all (validation data annotations take care of forcing the user to put something in).
This is easily done with Javascript like so:
function InitialiseForm() {
$('#Company').prop('selectedIndex', -1);
}
window.onload = InitialiseForm;
However, we have a few cases where the form isn't loaded entirely blank, and instead the pany field is initialised in the controller, like so:
modelObject.Company = "Coca Cola"
and in such cases we of course don't want the Javascript to execute and erase this.
What's the normal solution in such cases?
Share Improve this question edited Oct 16, 2013 at 13:12 hawbsl asked Oct 16, 2013 at 13:06 hawbslhawbsl 16.1k25 gold badges75 silver badges119 bronze badges 4- Well you need to somehow tell you set the value... – epascarello Commented Oct 16, 2013 at 13:07
-
Are you creating the dropdown with
@Html.DropDownList/For()
or some equivalent? – Mike H. Commented Oct 16, 2013 at 13:10 - @MikeHometchko edited in the code for the dropdownlist – hawbsl Commented Oct 16, 2013 at 13:13
- Try to check the 'selected' attribute on dropdown items. I remember that such attribute is added if mvc uses a pre-defined selection. – vortexwolf Commented Oct 26, 2013 at 19:21
5 Answers
Reset to default 3 +50My supposition was correct: the DropDownListFor
doesn't generate the selected
attribute if the initial value is null.
With empty pany it generates the following html:
<select id="Company" name="Company">
<option value="1">Coca-Cola</option>
<option value="2">Pepsi</option>
</select>
With selected pany html code is different:
<select id="Company" name="Company">
<option selected="selected" value="1">Coca-Cola</option>
<option value="2">Pepsi</option>
</select>
So you can use this javascript code and it will work:
$(function () {
if ($("#Company").find("option[selected]").length == 0) {
$("#Company").prop('selectedIndex', -1);
}
});
Also if your jquery version is earlier than 1.9.0, the option[selected]
expression may not work properly. The bug is fixed in 1.9.0, but in earlier versions functions like 'filter', 'children' and 'is' worked incorrectly, whereas 'find' and 'has' returned a correct result.
I faced a similar issue a few days ago, wanting to default my dropdown to the first index, unless it was selected at some point. I used a session variable as a remedy...something like this might do the trick:
var CurrentCompanyID = 1;
var gCompanyID = '@(Convert.ToInt32(Session["CompanyID"]))';
if (gCompanyID == null || gCompanyID == '' || gCompanyID == 0) {
CurrentCompanyID = 1;
}
else {
CurrentCompanyID = gCompanyID;
$("#CompanyDropDown").val(CurrentCompanyID);
}
$("#CompanyDropDown").change(function () {
CurrentCompanyID = $(this).val();
$.ajax({
url: "Controller/ChangeCompany",
cache: false,
data: { _pID: CurrentCompanyID },
success: function (result) {
console.log(result);
$("#CompanyForm").submit();
}
});
});
// Where:
public JsonResult ChangeCompany(int _pID)
{
Session["CompanyID"] = _pID;
return Json(Session["CompanyID"], JsonRequestBehavior.AllowGet);
}
...and for the Index() action of the current controller:
var _pID = Convert.ToInt32(Session["CompanyID"]);
var dataContext = new SERVERDataContext();
if (Session["CompanyID"] == null)
{
//Get Companies
return View(vm);
}
else
{
//Get Companies where Company.ID == _pID
return View(vm);
}
So essentially I'm setting the current value of the dropdown to the session variable's value. If I want to change the dropdown value, I simply assign a new value to the session var! While the session var is null or worthless, set the dropdown to my desired index.
Hope this helps.
here's one clean way to do that :
Add an optional label to the list, it will be selected if the model pany value is empty, otherwise the current value will be shown preselected (no need for the javaScript select code), also if the user dont choose a value he can't pass the validation :
@Html.DropDownListFor(Function(model) model.Company, TryCast(ViewData("Companies"), SelectList), "Select a pany", New With {Key .style = "blah blah;"})
@{
var listItems = new SelectList(new List<SelectListItem>
{
new SelectListItem { Value = "1", Text = "drink 1" },
new SelectListItem { Value = "2", Text = "drink 2" },
new SelectListItem { Value = "3", Text = "drink 3" }
}, "Value", "Text");
var selectedDrink = "";
}
@Html.DropDownListFor(x => selectedDrink, listItems, "--select drink--")
"--select drink--" Will be displayed unless the selected item is set.
(Code only written in View for brevity)
OPTION 1:
You can put the logics in the action method in the controler.
Ex: Controller
public ActionResult LoadForm()
{
var panies = new List<Company>();
var isSpecialCase = false;
if (default)
{
panies.Add(new Company {
CompanyId = 1,
CompanyName = "Coca Cola"
});
panies.Add(new Company
{
CompanyId = 2,
CompanyName = "Pepsi"
});
}
else if (yourSpecialCase)
{
isSpecialCase = true;
panies.Add(new Company {
CompanyId = 1,
CompanyName = "Coca Cola"
});
}
else
{
//define any other implementations...
}
ViewBag.IsSpecialCase = isSpecialCase;
ViewBag.Companies = panies;
return View();
}
Company Class
public class Company {
public int CompanyId { get; set; }
public string CompanyName { get; set; }
}
In your form (note that if it is a special case, the optional label will not be displayed)
@if (ViewBag.IsSpecialCase)
{
@Html.DropDownListFor(model => model.Data, new SelectList(ViewBag.Companies as List<Company>, "CompanyName", "CompanyId"))
}
else
{
@Html.DropDownListFor(model => model.Data, new SelectList(ViewBag.Companies as List<Company>, "CompanyName", "CompanyId"), "Select a pany...")
}
OPTION 2:
Create a custom drop down list (custom html helper)
Please refer the below links. link 1 link 2