How do I maintain drop down selections on a page with many dynamically named drop down lists in asp.net mvc 2?
I've read开发者_如何学编程 the links listed when I was creating this question. I think what I'm trying to do differs slightly. I am using ASP.NET MVC 2.
Apologies for the incoming wall of text. The most brief way I can think to ask this question is immediately below. After that I go into more of the why and how of the question.
[VERY QUICK POINT OF THE QUESTION] How do I return a dictionary as a JSON result from an action and what jquery/javascript could be used in the onLoad event of the drop down lists to search that JSON for a named element and if it is found, return the corresponding value and pre-select that value in the drop down list?
[BACKGROUND] I am working on creating a project for work where the user select an option from 2 initial drop downs. The first drop contains a list of pdf file names. The second drop downs contains a list of database queries associated with an alias name (they do not see sql...they see the name of the corresponding stored procedure or view). After the user has made these 2 selections the page reloads with many more drop downs below in 2 columns.
On the left column is a list of drop downs that all contain the same content: a list of the names of the text fields contained within the selected pdf (I am using CeTe software's Dynamic PDF to handle pdf interaction). On the right column will be a list of drop downs containing the field names of the selected query. Both columns will have an equal number of drop downs; the total number will be the number of fields on the pdf.
[PROBLEM] I can load the page fine and populate the drop downs with their respective data. The problem comes after the submit button is clicked and the data is posted. Since the drop downs are created dynamically, I'm using a naming convention to link which selections belong to the pdf fields and which belong to the db fields. On the action side, I iterate over the FormCollection and create a dictionary where the key is the name of the element posted and the value is the value of the element that was submitted. I only add entries to the dictionary for elements that have a non-null, non-empty value.
So far, I have all of that working. My issue, as you've probably guessed, is maintaining the selections when the page returns from the Action back to the view. I've got some really mutilated code that is close, but probably a world away from a good solution.
I will post the code I have that makes sense below. Another idea I have, that I've no clue how to go about doing is to put a function in the onLoad event of the drop down lists and goes to a json action and sends posts the name of the drop down calling the action/script (whatever this becomes). If the name submitted exists in the dictionary where I'm storing the previously submitted names & values of the drop down lists, the corresponding value that should be pre-selected is returned; otherwise nothing is returned and none of the drop down's values are pre-selected.
I don't know much about JSON, but if I could return the previously posted name/value dictionary as a JSON result to the page, I could use jquery to parse the json and handle the preselection where needed on the drop down.
See my current code below. It could be emulated by just creating stubs data for the SelectItemLists if you so cared. The current issue is that whatever the last name/value element is in the pre-selected dictionary is what is pre-selected for the rest of the list of drop downs.
Ex:
Selected values:
A FirstName
B LastName
C SSN
<no selection> <no selection>
<no selection> <no selection>
<no selection> <no selection>
<no selection> <no selection>
If the above is submitted, the result is the following:
A FirstName
B LastName
C SSN
C SSN
C SSN
C SSN
C SSN
Current code:
<% using (Html.BeginForm()) { %>
<%
List<SelectListItem> mainPdfFieldNames = (List<SelectListItem>)ViewData["PdfFieldNames"];
List<SelectListItem> mainDbFieldNames = (List<SelectListItem>)ViewData["DbFieldNames"];
Dictionary<String, String> fieldValue = (Dictionary<string, string>)ViewData["selectedFieldValues"] ?? new Dictionary<string, string>();
%>
<% for (int i = 0; i < mainPdfFieldNames.Count; i++)
{
String pdfPreselectValue = string.Empty;
String dbPreselectValue = string.Empty;
fieldValue.TryGetValue("PdfFieldNames" + i.ToString(), out pdfPreselectValue);
fieldValue.TryGetValue("DbFieldNames" + i.ToString(), out dbPreselectValue);
IDictionary<string, object> pdfHtmlAttrib = new Dictionary<string, object>();
IDictionary<string, object> dbHtmlAttrib = new Dictionary<string, object>();
List<SelectListItem> pdfFieldNames = mainPdfFieldNames;
List<SelectListItem> dbFieldNames = mainDbFieldNames;
%>
<%= Html.Encode(" PDF Selected value: " + pdfPreselectValue ) %>
<%= Html.Encode(" DB Selected value: " + dbPreselectValue) %>
<%
if (!String.IsNullOrEmpty(pdfPreselectValue))
{
pdfFieldNames.Find(p => p.Value.Equals(pdfPreselectValue)).Selected = true;
pdfHtmlAttrib.Add("selected", null);
}
if (!String.IsNullOrEmpty(dbPreselectValue))
{
dbFieldNames.Find(p => p.Value.Equals(dbPreselectValue)).Selected = true;
dbHtmlAttrib.Add("selected", null);
}
%>
Select PDF Field: <%=Html.DropDownList("PdfFieldNames" + i.ToString(), pdfFieldNames, "Select PDF Field", pdfHtmlAttrib)%>
Select Database Field: <%=Html.DropDownList("DbFieldNames" + i.ToString(), dbFieldNames, "Select Database Field", dbHtmlAttrib)%>
<br />
<%
}%>
<input type="submit" value="Submit" />
<% } %>
MAJOR EDIT 1 OMITTED TO MAKE ROOM FOR SOLUTION
I've decided to go a different route with this. I think this might be more simplified in the end. After the view posts to the action, I create a string variable from the Dictionary I was previously using. This string is put in ViewData and on the page is a hidden field. I have a javascript function that grabs this field and parses it. The nameValue field has the format of "fieldname,fieldvalue;fieldname,fieldvalue;fieldname,fieldvalue".
I am posting some test code below. It's actually a full html page that I'm using to develop this process bit by bit. My only remaining issue is triggering code to load after the page has been loaded. This code will select all drop downs on the page, iterate over them, and pass the name of the drop down to the function I've created that handles pre-selecting a value on the drop down based on it's name and whether that name exists in the nameValue hidden field on the page.
So the problem is that on validation failure you want to show the view again and keep the previous selections made in the dynamic-cascading selects?
Instead of trying to re-automate the select/cascades on the client, why not render all the selects on the server and let ModelState handle the previous selections. All you have to do is make sure the right options are in each level.
Based on your question this is what im assuming your looking for.
CONTROLLER
public class SelectListings
{
public static SelectList Listing1(int key = 1)
{
var listings = new Dictionary<string, string>
{
{"Option 1", "_opt1"},
{"Option 2", "_opt2"},
};
var list = new SelectList(listings, "Value", "Key", key != 1 ? key : key);
return list;
}
}
ActionResult PageBegin()
{
ViewData["selectList1"] = SelectListings.Listing1();
ViewData["selectList2"] = SelectListings.Listing2();
return View(ViewData);
}
ActionResult PageSubmit(int listKey1, int listKey2)
{
ViewData["selectList1"] = SelectListings.Listing1(listKey1);
ViewData["selectList2"] = SelectListings.Listing2(listKey2);
return View("PageBegin", ViewData);
}
VIEW
<% var selectedList1 = (SelectList)ViewData["selectList1"];
var selectedList2 = (SelectList)ViewData["selectList2"]; %>
<%= Html.DropDownList("selectList1", selectedList1)%>
<%= Html.DropDownList("selectList2", selectedList2)%>
<%!-- include if statement here to check if value has changed --%>
Your Selected Value for list1 is : <%= selectedList1.DataValueField %>
Your Selected Value for list2 is : <%= selectedList2.DataValueField %>
Wrote this from the top of my head, it might not compile first time.
SOLVED ISSUE
I expanded this sample html page to illustrate the issue better.
A javascript error is being thrown somewhere, but I haven't located it yet. The code still works and the correct drop downs are pre-selected based on the data in the postedFieldValues hidden field.
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta name="generator" content=
"HTML Tidy for Windows (vers 14 February 2006), see www.w3.org">
<title></title>
</head>
<body>
<form>
<input id="postedFieldValues" name="postedFieldValues" type="hidden"
value=
"PdfFieldNames0,f1-10;DbFieldNames0,LastName;PdfFieldNames1,f1-12;DbFieldNames1,LoanNumber;PdfFieldNames2,f1-15;DbFieldNames2,SSN;">
</form>
<p>
Values stored in the postedFieldValues hidden field for this example
are:<br>
"PdfFieldNames0,f1-10;DbFieldNames0,LastName;PdfFieldNames1,f1-12;DbFieldNames1,LoanNumber;PdfFieldNames2,f1-15;DbFieldNames2,SSN;"
</p><br>
<script type="text/javascript" src=
"http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js">
</script><script type="text/javascript">
if(typeof Jquery == 'undefined')
document.write(unescape("%3Cscript src ='jquery-1.4.4.js'" + "type='text/javascript'%3E%3C/script%3E"));
function PreselectValue(name) {
var values = $("[id=postedFieldValues]");
var ddl = $("[id="+name+"]");
//alert(values.val());
//alert(ddl.val());
if( values == null || values == '')
return;
var pairs = values.val().split(";");
for (var i = 0; i < pairs.length; i++) {
//name is in index 0
//value is in index 1
var individualNameValuePair = pairs[i].split(",");
if (name == individualNameValuePair[0]) {
ddl.val(individualNameValuePair[1]);
}
}
}
</script>Select PDF Field: <select id="PdfFieldNames0" name=
"PdfFieldNames0">
<option value="">
Select PDF Field
</option>
<option value="f1-1">
f1-1
</option>
<option value="f1-10">
f1-10
</option>
<option value="f1-11">
f1-11
</option>
<option value="f1-12">
f1-12
</option>
<option value="f1-13">
f1-13
</option>
<option value="f1-14">
f1-14
</option>
<option value="f1-15">
f1-15
</option>
<option value="f1-16">
f1-16
</option>
</select> Select Database Field: <select id="DbFieldNames0" name=
"DbFieldNames0">
<option value="">
Select Database Field
</option>
<option value="FirstName">
FirstName
</option>
<option value="LastName">
LastName
</option>
<option value="SSN">
SSN
</option>
<option value="LoanNumber">
LoanNumber
</option>
</select><br>
Select PDF Field: <select id="PdfFieldNames1" name="PdfFieldNames1">
<option value="">
Select PDF Field
</option>
<option value="f1-1">
f1-1
</option>
<option value="f1-10">
f1-10
</option>
<option value="f1-11">
f1-11
</option>
<option value="f1-12">
f1-12
</option>
<option value="f1-13">
f1-13
</option>
<option value="f1-14">
f1-14
</option>
<option value="f1-15">
f1-15
</option>
<option value="f1-16">
f1-16
</option>
</select> Select Database Field: <select id="DbFieldNames1" name=
"DbFieldNames1">
<option value="">
Select Database Field
</option>
<option value="FirstName">
FirstName
</option>
<option value="LastName">
LastName
</option>
<option value="SSN">
SSN
</option>
<option value="LoanNumber">
LoanNumber
</option>
</select><br>
Select PDF Field: <select id="PdfFieldNames2" name="PdfFieldNames2">
<option value="">
Select PDF Field
</option>
<option value="f1-1">
f1-1
</option>
<option value="f1-10">
f1-10
</option>
<option value="f1-11">
f1-11
</option>
<option value="f1-12">
f1-12
</option>
<option value="f1-13">
f1-13
</option>
<option value="f1-14">
f1-14
</option>
<option value="f1-15">
f1-15
</option>
<option value="f1-16">
f1-16
</option>
</select> Select Database Field: <select id="DbFieldNames2" name=
"DbFieldNames2">
<option value="">
Select Database Field
</option>
<option value="FirstName">
FirstName
</option>
<option value="LastName">
LastName
</option>
<option value="SSN">
SSN
</option>
<option value="LoanNumber">
LoanNumber
</option>
</select><br>
Select PDF Field: <select id="PdfFieldNames3" name="PdfFieldNames3">
<option value="">
Select PDF Field
</option>
<option value="f1-1">
f1-1
</option>
<option value="f1-10">
f1-10
</option>
<option value="f1-11">
f1-11
</option>
<option value="f1-12">
f1-12
</option>
<option value="f1-13">
f1-13
</option>
<option value="f1-14">
f1-14
</option>
<option value="f1-15">
f1-15
</option>
<option value="f1-16">
f1-16
</option>
</select> Select Database Field: <select id="DbFieldNames3" name=
"DbFieldNames3">
<option value="">
Select Database Field
</option>
<option value="FirstName">
FirstName
</option>
<option value="LastName">
LastName
</option>
<option value="SSN">
SSN
</option>
<option value="LoanNumber">
LoanNumber
</option>
</select><br>
Select PDF Field: <select id="PdfFieldNames4" name="PdfFieldNames4">
<option value="">
Select PDF Field
</option>
<option value="f1-1">
f1-1
</option>
<option value="f1-10">
f1-10
</option>
<option value="f1-11">
f1-11
</option>
<option value="f1-12">
f1-12
</option>
<option value="f1-13">
f1-13
</option>
<option value="f1-14">
f1-14
</option>
<option value="f1-15">
f1-15
</option>
<option value="f1-16">
f1-16
</option>
</select> Select Database Field: <select id="DbFieldNames4" name=
"DbFieldNames4">
<option value="">
Select Database Field
</option>
<option value="FirstName">
FirstName
</option>
<option value="LastName">
LastName
</option>
<option value="SSN">
SSN
</option>
<option value="LoanNumber">
LoanNumber
</option>
</select><br>
Select PDF Field: <select id="PdfFieldNames5" name="PdfFieldNames5">
<option value="">
Select PDF Field
</option>
<option value="f1-1">
f1-1
</option>
<option value="f1-10">
f1-10
</option>
<option value="f1-11">
f1-11
</option>
<option value="f1-12">
f1-12
</option>
<option value="f1-13">
f1-13
</option>
<option value="f1-14">
f1-14
</option>
<option value="f1-15">
f1-15
</option>
<option value="f1-16">
f1-16
</option>
</select> Select Database Field: <select id="DbFieldNames5" name=
"DbFieldNames5">
<option value="">
Select Database Field
</option>
<option value="FirstName">
FirstName
</option>
<option value="LastName">
LastName
</option>
<option value="SSN">
SSN
</option>
<option value="LoanNumber">
LoanNumber
</option>
</select><br>
Select PDF Field: <select id="PdfFieldNames6" name="PdfFieldNames6">
<option value="">
Select PDF Field
</option>
<option value="f1-1">
f1-1
</option>
<option value="f1-10">
f1-10
</option>
<option value="f1-11">
f1-11
</option>
<option value="f1-12">
f1-12
</option>
<option value="f1-13">
f1-13
</option>
<option value="f1-14">
f1-14
</option>
<option value="f1-15">
f1-15
</option>
<option value="f1-16">
f1-16
</option>
</select> Select Database Field: <select id="DbFieldNames6" name=
"DbFieldNames6">
<option value="">
Select Database Field
</option>
<option value="FirstName">
FirstName
</option>
<option value="LastName">
LastName
</option>
<option value="SSN">
SSN
</option>
<option value="LoanNumber">
LoanNumber
</option>
</select><br>
Select PDF Field: <select id="PdfFieldNames7" name="PdfFieldNames7">
<option value="">
Select PDF Field
</option>
<option value="f1-1">
f1-1
</option>
<option value="f1-10">
f1-10
</option>
<option value="f1-11">
f1-11
</option>
<option value="f1-12">
f1-12
</option>
<option value="f1-13">
f1-13
</option>
<option value="f1-14">
f1-14
</option>
<option value="f1-15">
f1-15
</option>
<option value="f1-16">
f1-16
</option>
</select> Select Database Field: <select id="DbFieldNames7" name=
"DbFieldNames7">
<option value="">
Select Database Field
</option>
<option value="FirstName">
FirstName
</option>
<option value="LastName">
LastName
</option>
<option value="SSN">
SSN
</option>
<option value="LoanNumber">
LoanNumber
</option>
</select><br>
<br>
<form>
PAGE HAS LOADED. <script type="text/javascript">
$(document).ready(function () {
//alert('testing');
$('select').each(function(index) {
var id = $(this).attr('id');;
PreselectValue(id);
});
//alert('after iterate');
});
</script>
</form>
</body>
</html>
精彩评论