I have following three dropdowns in my MVC View.
@Html.DropDownListFor(m => m.Zone.LocationId,
new SelectList(Model.Locations, "Id", "Description"),
"--Select Location--",
new { @class = "form-control", id = "ddlLocations",
onchange = "Change(this)" })
@Html.DropDownListFor(m => m.Zone.DepartmentId,
new SelectList(new List<string>()),
new { @class = "form-control", id = "ddlDepartments" })
@Html.DropDownListFor(m => m.Zone.AreaId,
new SelectList(new List<string>()),
new { @class = "form-control", id = "ddlAreas" })
Locations come from my ViewModel according to the access of loggedin user. Department gets updated according to the selection made in locations.
Following is the code for same.
function Change(control) {
let item = $(control).val();
if (item !== undefined && item !== "")
bindDdl("/api/get/DepartmentsByLocation?locationId=" + $(control).val(),
$("#ddlDepartments"),
"--Select Department--");
else
$("#ddlDepartments").empty();
}
function bindDdl(url, control, displayText, hiddenControl) {
$(control).empty();
$.ajax({
type: "get",
url: url,
dataType: "",
success: function (data) {
let ddl = $(control);
ddl.append('<option value=>'
+ displayText + '</option >');
for (var i = 0; i < data.length; i++) {
ddl.append('<option value=' + data[i].id + '>' + data[i].description + '</option >');
}
if ($(hiddenControl).val() != "0")
ddl.val($(hiddenControl).val());
}
});
}
My Areas dropdown gets populated from jquery with the following code.
bindDdl("/api/get/Areas", $("#ddlAreas"), "--Select Area--");
Everything works fine till here, now I have a problem in two situations, when user tries to edit and when a user finishes adding a record. In both the situations I want to pre set the values of location, department and areas. In case of edit, all values come from the model, incase of Save, I want to preserve the state of dropdowns to previously selected ones, so that the user need not again and again select these values. Following is my code in controller.
public ActionResult Index(int id = 0)
{
ZoneViewModel data = new ZoneViewModel();
if (id > 0)
data.Zone = _unitOfWork.Zones.GetDtoById(id);
if (data.Zone == null)
data.Zone = new ZoneDto();
data.Locations =
(List<LocationDto>)_unitOfWork.Locations.GetLocationsByUserId(UserId);
if (data.Locations.Count == 1)
data.Zone.LocationId = data.Locations[0].Id;
if (id <= 0 && Session["LocationId"] != null)
{
data.Zone.LocationId = (int)Session["LocationId"];
data.Zone.DepartmentId = (int)Session["DepartmentId"];
data.Zone.AreaId = (int)Session["AreaId"];
}
return View("Zone", data);
}
Now, the locations dropdown value is getting selected without any problem as it is coming from the model, I have to auto select location and populate departments if the user has access to only one location. Following is the code for same.
if ($("#ddlLocations > option").length === 2)
Change($("#ddlLocations"));
I have the following jquery code to pre-select the items in Areas and department in my view, this particlar code is not working, no errors. By defaut the first item is getting selected.
if (@Model.Zone.DepartmentId > 0)
$("#ddlDepartments").val("@Model.Zone.DepartmentId.ToString()");
if (@Model.Zone.AreaId > 0)
$("#ddlAreas").val('@Model.Zone.AreaId.ToString()');
Not sure why department and areas values are not getting selected, checked the values in model by logging in console, values are getting passed perfectly, but Jquery is not selecting the dropdownlist values for some reason.
Found out the problem and solution. Problem is that ajax calls are asynchronous because of which my code is trying to set the dropdownlists values before they are populated. Got clues from the following answers
Setting selected value of a Select using JQuery from an MVC model property
Wait until all jQuery Ajax requests are done?
javascript function wait until another function to finish
Modified my code as follows to address the issue, please bear with me as the code looks ugly, decided to refactor it later, to meet deadlines.
$.when(
bindDdl("/api/get/[email protected]()",
$("#ddlLocations"),
"--Select Location--",
undefined,
false),
bindDdl("/api/get/Areas", $("#ddlAreas"), "--Select Area--")).done(function(a1) {
if (@Model.Zone.AreaId > 0)
$("#ddlAreas").val('@Model.Zone.AreaId.ToString()');
if (@Model.Zone.LocationId > 0)
$("#ddlLocations").val('@Model.Zone.LocationId');
if (@Model.Zone.DepartmentId > 0) {
$.when(bindDdl("/api/get/DepartmentsByLocation?locationId=" + $("#ddlLocations").val(),
$("#ddlDepartments"),
"--Select Department--")).done(function() {
$("#ddlDepartments").val('@Model.Zone.DepartmentId.ToString()');
});
}
else
{
let ctrl = $("#ddlLocations");
if ($(ctrl)[0].length === 2) {
$(ctrl)[0].selectedIndex = "1";
$(ctrl).trigger('change');
}
}
});
});
function Change(control) {
let item = $(control).val();
if (item !== undefined && item !== "")
bindDdl("/api/get/DepartmentsByLocation?locationId=" + $(control).val(),
$("#ddlDepartments"),
"--Select Department--");
else
$("#ddlDepartments").empty();
}
And the bindDdl function is as follows.
function bindDdl(url, control, displayText, hiddenControl, raiseEvent) {
console.log(displayText);
console.log(typeof raiseEvent);
raiseEvent = (typeof raiseEvent === 'undefined') ? true : raiseEvent;
console.log(raiseEvent);
$(control).empty();
return $.ajax({
type: "get",
url: url,
dataType: "",
success: function (data) {
let ddl = $(control);
ddl.append('<option value=>' + displayText + '</option >');
for (var i = 0; i < data.length; i++) {
ddl.append('<option value=' + data[i].id + '>' + data[i].description + '</option >');
}
if ($(hiddenControl).val() != "0")
ddl.val($(hiddenControl).val());
if ($(control)[0].length === 2 && raiseEvent) {
$(control)[0].selectedIndex = "1";
$(control).trigger('change');
}
}
});
}