I have 2 dropdownlists, the second (department) cascades from the first (division). I use a jquery script to update the second drop down list. When the user clicks submit, the underlying model is updated, apart from the new value for department. 2 ideas I have for fixing this are; a) Generate a postback. Prefer not to do this because of bad user experience. b) With a JQuery change event, make a call to server side and set a ViewData variable that I can use to update the field in the model later.
However there must be a better way. This is the view;
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/AdminAccounts.master"
Inherits="System.Web.Mvc.ViewPage<SHP.WebUI.Models.EmployeeViewModel>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Add
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="AdminAccountsContent" runat="server">
<% using (Html.BeginForm("Add", "Employee")) {%>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Add Employee</legend>
<table>
<tr>
<td align="right">
<%: Html.LabelFor(model => model.Employee.UserName)%>
</td>
<td>
<%: Html.EditorFor(model => model.Employee.UserName)%>
<%: Html.ValidationMessageFor(model => model.Employee.UserName)%>
</td>
</tr>
<tr>
<td align="right">
<%: Html.LabelFor(model => model.Division.DivisionId) %>
</td>
<td>
<%: Html.DropDownListFor(model => model.Division.DivisionId, Model.DivisionSelectList, "<--Select-->")%>
<%: Html.ValidationMessageFor(model => model.Division.DivisionId)%>
</td>
</tr>
<tr>
<td align="right">
<%: Html.LabelFor(model => model开发者_如何学编程.Department.DepartmentId) %>
</td>
<td>
<%: Html.DropDownListFor(model => model.Department.DepartmentId, Model.DepartmentSelectList, "<--Select-->")%>
<%: Html.ValidationMessageFor(model => model.Department.DepartmentId) %>
</td>
</tr>
<tr>
<td align="center" colspan="2" style="padding-top:20px;">
<input type="submit" value="Save" /></td>
</tr>
</table>
<% if (ViewData["LastPerson"].ToString().Length > 0)
{ %>
<p>
At time <% Response.Write(DateTime.Now.ToString("T")); %>
- You have just entered <%Response.Write(ViewData["LastPerson"].ToString()); %>.
</p>
<%} %>
</fieldset>
<% } %>
<div>
<%: Html.ActionLink("Back to List", "Index") %>
</div>
<script language="javascript" type="text/javascript">
//Hook onto the DivisionId list's onchange event
$("#Division_DivisionId").change(function () {
//build the request url
var url = '<%: Url.Content("~/")%>' + "Employee/GetDepartments";
//fire off the request, passing it the id which is the DivisionId's selected item value
$.getJSON(url, { divisionId: $("#Division_DivisionId").val() }, function (data) {
//Clear the Department list
$("#Department_DepartmentId").empty();
$("#Department_DepartmentId").append("<option><--Select--></option>");
//Foreach Department in the list, add a department option from the data returned
$.each(data, function (index, optionData) {
$("#Department_DepartmentId").append(
"<option value='" + optionData.DepartmentId + "'>" +
optionData.DepartmentName + "</option>");
});
});
}).change();
</script>
I'd make a partial view that generates the second drop down. That would look something like this:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<SHP.WebUI.Models.EmployeeViewModel>" %>
<%: Html.DropDownListFor(model => model.Department.DepartmentId, Model.DepartmentSelectList, "<--Select-->") %>
It's the Inherits
attribute that make it strongly typed, your page above is also strongly typed.
While you are at it, change this code:
<%: Html.ValidationMessageFor(model => model.Department.DepartmentId) %>
into:
<%: Html.Partial("<TheNameOfYourDropDownPartial>", Model) %>
Next, to add a change event to the division drop down change this line of code:
<%: Html.DropDownListFor(model => model.Division.DivisionId, Model.DivisionSelectList, "<--Select-->")%>
into:
<%: Html.DropDownListFor(model => model.Division.DivisionId, Model.DivisionSelectList, "<--Select-->", new { onchange = "divisionChanged()" })%>
And now, let's add the divisionChanged()
javascript function. It would look something like this:
<script type="text/javascript">
function divisionChanged() {
var divisionId = $("select[name=Division.DivisionId]").val();
$.ajax({
data: { DivisionId: divisionId },
dataType: "html",
success: function (data, textStatus, xmlRequest) {
$("select[name=Department.DepartmentID]").replaceWith(data);
},
type: "POST",
url: "/Employee/GetDepartmenDropDown});
}
</script>
That function makes an ajax post to your GetDepartmentDropDown action and takes the returned html and replaces the department drop down with it.
Your GetDepartmentDropDown will have to take whatever data you need to recreate the EmloyeeViewModel
you passed in the view in the first place, (this data should be included in the data
property in the ajax call in the javascript function) and then return something like this:
var model = new EmployeeViewModel(DivisionId);
return PartialView("<TheNameOfYourDropDownPartial>", model);
You shouldn't initialize the model in the return statement of course, it's just there to give an idea of what needs to be done.
That should do it I think. Then when you post the form the receiving action should be able to pick up the value.
Hope it helps.
What follows is what has worked for me. It is not the best code I have written, but it was the first jQuery and MVC app I ever did. Despite all that, it works, even with three cascading ddls.
Ie, user choose an EncephalitisType, then an EncephalitisSubType, then an InfectiousAgent (if the type and the subtype involved infectious agents).
It strikes me that the Model Binder is able to marry up the DepartmentID property, and the issue would probably be one of name. I would suggest looking at the following thread:
ASP.NET MVC 2 Dots Replaced With Underscore In Element Name
They had an issue with names, and the discussion might help you solve your problem.
Sorry I can't be of more assistance, as I am upgrading a site with 1800 pages to be W3C WAI compliant. So I am brain dead.
For what it is worth, a sketch of my app that works follows, you might find something there that helps. Sorry, too tired to look in detail.
==============
Illness Details DDLs
This is my view (both view and jquery code have been simplified to show only the loading of the values; there was a lot of extra code to hide and show each ddl according to what the user did that is unnecessary for getting to the bottom of your problem):
<fieldset>
<legend>Illness Details</legend>
<p>
<label for="IdEncephalitisType">
Type Of Encephalitis:</label>
<%= Html.DropDownList("IdEncephalitisType", Model.EncephalitisTypes)%>
<%= Html.ValidationMessage("IdEncephalitisType", "*") %>
</p>
<p>
<label id="lblEncephalitisSubType" for="IdEncephalitisSubType">
Sub Type of Encephalitis:</label>
<%= Html.DropDownList("IdEncephalitisSubType", Model.EncephalitisSubTypes)%>
<%= Html.ValidationMessage("IdEncephalitisSubType", "*") %>
</p>
<p>
<label id="lblInfectiousAgent" for="IdInfectiousAgent">
Infectious Agent:</label>
<%= Html.DropDownList("IdInfectiousAgent", Model.InfectiousAgents) %>
<%= Html.ValidationMessage("IdInfectiousAgent", "*") %>
</p>
</fieldset>
Note also that one difference is that your code use the new type safe helpers (Html.DropDownListFor) whereas mine comes from MVC 1 days.
This is the javascript:
<script type="text/javascript">
$('document').ready(function() {
var ddlEt = $("#IdEncephalitisType");
var ddlEst = $("#IdEncephalitisSubType");
var ddlIa = $("#IdInfectiousAgent");
var sel = ddlEt.val();
// debugger
if (sel === "2") {
pIa.fadeOut('slow');
}
// Change Event Handler
$("#IdEncephalitisType").change(function() {
var selection = $(this).val();
ddlEst.val("0");
ddlIa.val("0");
if ((selection === "0") || (selection === "3")) {
// do sumat
}
else {
var url = "/Register/Illness/CascadedDdlSubType/" + selection;
AjaxEncephalitisSubTypes(url);
}
});
// Change Event Handler
$("#IdEncephalitisSubType").change(function() {
ddlIa.val("0");
var selEst = $('#IdEncephalitisSubType option:selected').val();
if (selEst !== "") {
if (($("#IdEncephalitisType").val() == "1") &&
((selEst === "1") || (selEst == "2"))) {
var url = "/Register/Illness/CascadedDdlInfectiousAgent/" + selEst;
AjaxInfectiousAgents(url);
}
}
});
function AjaxEncephalitisSubTypes(urlx) {
$.ajax({ type: "GET", url: urlx,
contentType: "application/json; charset=utf-8", dataType: "json", success: function (json) {
ddlEst.empty();
ddlIa.empty();
PrependDdlDefaults(ddlEst);
var i = 0;
$.each(json, function (index, optionData) {
ddlEst.append("<option value='"
+ optionData.Id
+ "'>" + optionData.Name
+ "</option>");
i++;
});
ddlEst.val("0");
}
});
}
function AjaxInfectiousAgents(urlx) {
$.ajax({ type: "GET", url: urlx,
contentType: "application/json; charset=utf-8", dataType: "json", success: function (data) {
var i = 0;
ddlIa.empty();
PrependDdlDefaults(ddlIa);
$.each(data, function (index, optionData) {
ddlIa.append(
"<option value='"
+ optionData.Id
+ "'>" + optionData.Name
+ "</option>");
i++;
});
}
});
ddlIa.val("");
}
function PrependDdlDefaults(ddl) {
ddl.prepend(
"<option value='"
+ ""
+ "'><i>" + " --- Please choose... --- "
+ "</i></option>");
}
});
</script>
This is my Controller:
// POST: /Illness/Input
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Input(IllnessDetail ill)
{
ill.username = User.Identity.Name;
ill.DateCreated = DateTime.Now.Date;
IllnessDetailFormViewModel mfv = new IllnessDetailFormViewModel(ill);
if (ModelState.IsValid)
{
try
{
idr.Add(ill);
idr.Save();
return RedirectToAction("Current", new { nameUser = User.Identity.Name });
}
catch
{
ModelState.AddRuleViolations(mfv.IllnessDetail.GetRuleViolations());
}
}
return View(mfv);
}
IllnessDetailFormViewModel(ill) is a FormViewModel class and IllnessDetail is the type that is delivered by the Repository.
精彩评论