參考網址:
列表類的綁定:https://www.cnblogs.com/mrtiny/p/5807489.html
js獲取表單數據:https://www.jb51.net/article/90756.htm
ajax提交表單數據:https://blog.csdn.net/CrackLibby/article/details/80013057
在mvc中,表單的輸入字段綁定到數據模型上的過程是自動完成的,本文進行簡單地說明。
注:我用的是vs2015,mvc5,測試用的是360瀏覽器
我的目標是在一個頁面上,彈出來一組輸入項(form表單),用戶在輸入後點提交時,後臺能夠獲取到輸入的內容。如果所有處理成功,就刷新頁面,使輸入的內容更新到頁面上(此時彈出的輸入項會被隱藏),如果失敗,就保持當前的狀態。這樣做有個好處是,如果失敗,則當前的頁面完成保持當前的輸入狀態,沒有任務改變,也沒有任何刷新,感受會好很多。
爲了實現這個目標,需要有幾個步驟:
1. 這個表單在頁面加載時處於隱藏狀態,在點擊一個功能按鈕時,顯示這個表單。這個步驟簡單,後面就不說了
2. 點擊表單中的“提交”按鈕時,用js獲取表單的輸入數據,然後使用ajax提交數據
3. 後臺收到提交的數據時進行處理,並返回處理結果
4. ajax收到處理結果後,如果是失敗就進行提示,如果成功,就刷新頁面
一個一個步驟來。
2.1. 用js獲取表單中輸入的數據
參數前面的網址,直接使用就行了,但是那個網址中的代碼少了對select輸入的處理,所以我這裏對它進行了少許修改,修改後的代碼如下:
// https://www.jb51.net/article/90756.htm
//獲取指定form中的所有的<input>對象
function getFormElements(formId) {
var form = Gho(formId);
var elements = new Array();
var tagElements = form.getElementsByTagName('input');
for (var j = 0; j < tagElements.length; j++) {
elements.push(tagElements[j]);
}
tagElements = form.getElementsByTagName('select');
for (var j = 0; j < tagElements.length; j++) {
elements.push(tagElements[j]);
}
return elements;
}
//獲取單個input中的【name,value】數組
function checkboxSelector(element, hoId) {
if (element.checked)
return [hoId, element.value];
}
// 單個select的選中項
function selectSelector(element, hoId) {
for (var i = 0; i < element.length; i++)
{
if (element[i].selected == true)
return [hoId, element[i].value];
}
}
function getFormInput(element) {
var hoId = element.name;
if (hoId == null || hoId == "")
hoId = element.id;
if (hoId == null || hoId == "")
{
return null;
}
switch (element.type.toLowerCase()) {
case 'submit':
case 'hidden':
case 'password':
case 'text':
return [hoId, element.value];
case 'checkbox':
case 'radio':
return checkboxSelector(element, hoId);
case 'select-one':
return selectSelector(element, hoId);
}
return false;
}
/*
組合URL
*/
function serializeElement(element) {
var method = element.tagName.toLowerCase();
var parameter = getFormInput(element);
if (parameter == null)
return;
if (parameter) {
var key = encodeURIComponent(parameter[0]);
if (key.length == 0) return;
if (parameter[1].constructor != Array)
parameter[1] = [parameter[1]];
var values = parameter[1];
var results = [];
for (var i = 0; i < values.length; i++) {
results.push(key + '=' + encodeURIComponent(values[i]));
}
return results.join('&');
}
}
//調用方法
function serializeForm(formId) {
var elements = getFormElements(formId);
var queryComponents = new Array();
for (var i = 0; i < elements.length; i++) {
var queryComponent = serializeElement(elements[i]);
if (queryComponent)
queryComponents.push(queryComponent);
}
return queryComponents.join('&');
}
除了添加selectSelector()之外,對函數的名稱進行了修改,key由單一的元素名稱修改成了元素的名稱和ID號二選一。
調用serializeElement()之後,輸出的就是用 & 號連接起來的經過url編碼的鍵值對了,所以它可以直接放在 url 的後面做爲參數,即 http://serverip/mytask?<formdata>
其中的 <formdata> 表示 serializeElement() 的返回數據
2.2 用ajax提交數據
先看js代碼:
function AddProperty_Submit()
{
var formData = "";
formData = serializeForm("prpAddForm");
var errMsg = "";
var curUrl = GetPageUrlBase(false);
var urlString = curUrl + 'AddProperty';
urlString += "?" + formData;
$.ajax(
{
type: "POST",
url: urlString,
contentType: "text/javascript", // request的數據類型是json
dataType: "json", // 返回的數據類型是json
//data: formData,
beforeSend: function () {
// 發送之前會進入到這個函數中,如果返回了false,就不會發送了
//return false;
return true;
},
success: function (data) {
// 由於上面設置了"json",所以這裏的data就是一個json對象了,服務器返回{}時,這裏不會進到此函數中
// 所以一旦進來,就說明確實拿到了標定的json數據
g_isAddSubmited = false;
if (data == null || data == "" || data == "{}") {
errMsg = "未知錯誤,請重試";
alert(errMsg);
return;
}
if (data["opeResult"] == 0) {
// 提交成功,就刷新頁面
location.reload(true);
return;
}
// 失敗
errMsg = data["errmsg"];
alert(errMsg);
},
error: function (errMsg) {
console.log(errMsg);
}
});
}
本來我以爲應該是要把表單數據放在 data 項中,但實際上我那樣它不成功,而是應該放在url的參數裏。最後的url類似這樣的格式:
http://serverip/AddProperty?name=aa&defval=bb
其中 AddProperty 是control中的對應action,由於這個action是在js中指定的,所以html表單中指定的action名稱就沒啥重要的了。
這裏要說明的一個情況,因爲這個表單是在一個頁面上的,而這個頁面上可能存在多個表單,還有就是這個頁面綁定的數據模型不是這個表單所要求的,同時因爲多個表單也不可能強綁定多個數據模型,所以從表單上來說,沒辦法直接指定要綁定的數據模型。
3. 後臺對數據的處理
爲了方便,action的參數還是要採用數據模型會方便很多,對程序維護會非常有利,所以還是往這方面去靠。
經過上面的網址來看,似乎並不難,只要數據模型的字段名稱和表單的字段表名一樣就可以了。數據模型定義如下(其實這裏應該簡化一下能夠說明問題就行了,但那樣要改來改去的,所以我就把這個輸入的所有內容全部貼出來了,省得改):
public class PropertyAddViewModeo
{
// 添加列表類的綁定值:https://www.cnblogs.com/mrtiny/p/5807489.html
// 只對修改有效
public int prpId { get; set; }
[Display(Name = "顯示名稱")]
public string prpDesc { get; set; }
// 鍵名
[Display(Name = "字段名稱")]
public string prpName { get; set; }
// 輸入方式
public int prpSubType { get; set; }
public string prpValues { get; set; }
public string prpDefValue { get; set; }
public List<int> toPrpGroup { get; set; }
}
這裏除了最後一個toPrpGroup之外,其它的都簡單,表單如下代碼(注:爲了減少代碼,這裏簡化了一些無關的輔助內容,以及排版代碼):
<div id="divPrpAdd" style="display:none;position:absolute;z-index:1;background-color:honeydew;width:800px;min-height:600px;border:1px solid black;padding:8px;">
@using (Html.BeginForm("AddProperty", "Manage", FormMethod.Post, new { id = "prpAddForm" }))
{
<input type="hidden" name="prpId" id="prpId" value="" />
<label>屬性名稱:</label> <input type="text" name="prpDesc" id="prpDesc" />
<label>字段名稱:</label> <input type="text" name="prpName" id="prpName" />
<label>輸入方式:</label>
<select name="prpSubType" id="prpSubType">
<option value="0">輸入</option>
<option value="1" selected>選擇</option>
</select>
<label>屬性值列表:</label> <input type="text" name="prpValues" id="prpValues" />
<label>缺省值:</label> <input type="text" name="prpDefValue" id="prpDefValue" />
<label>加入到屬性組:</label>
<div id="prpGroupList">
<input type="checkbox" id="toPrpGroup[0]" name="toPrpGroup[0]" value="3">
<input type="checkbox" id="toPrpGroup[1]" name="toPrpGroup[1]" value="4">
</div>
<input type="button" style="min-width:80px;" value="確定" onclick="AddProperty_Submit();" />
<input type="button" style="min-width:80px;" value="取消" onclick="AddProperty_Cancel();" />
}
</div>
這裏注意的是最後的checkbox,它實際上是動態生成的,其個數不確定,但至少會有一個。爲了和數據模型的綁定,參考上面的網址,其id採用數組的方式,名稱和數據模型中的字段名稱也保持一致,均爲 toPrpGroup。
在action中的處理函數僅用於測試,代碼如下:
[HttpPost]
public string AddProperty(PropertyAddViewModeo model)
{
return CreateResultString(1, "組名稱已經存在了,不允許重複");
}
不看處理代碼,只看參數是否獲取到了表單數據,當界面輸入如下:
這裏注意最後的兩個選擇框,acion的model參數內容如下所示:
獲取的這些數據全都沒錯,現在不選“車牌相關”而只選中“司機相關”,則看獲取到的數據如下:
這樣就沒有數據了,但是從表單中的確實獲取到它的值了,看js中formData變量的值:"prpId=-1&prpDesc=aa&prpName=bb&prpValues=cc&prpDefValue=dd&toPrpGroup%5B1%5D=4&prpSubType=1"
這就有點麻煩了。對於數據模型的定義,我也參考上面的那個網址添加了構造函數並在其中對toPrpGroup進行了初始化new,通過多次嘗試,這個初始化對結果沒有任何影響,也就是說,是否有這個初始化,結果都是一樣的。
從這裏看,如果是從0開始選擇,是可以正常獲取到值的,但如果不是從0開始,就獲取不到它的值,同樣,我估計如果中間有沒選中的,則後面的值也獲取不到。
如果只是這個不能獲取到值,就顯然有點不爽,於是就把數據的名稱改掉,如下所示:
<input type="checkbox" id="toPrpGroup" name="toPrpGroup" value="3">
<input type="checkbox" id="toPrpGroup" name="toPrpGroup" value="4">
這樣改過之後,即名稱不再使用數組的方式,結果就可以了,此時,如果兩個都選中,則formData的值如下:
"prpId=-1&prpDesc=aa&prpName=bb&prpValues=cc&prpDefValue=dd&toPrpGroup=3&toPrpGroup=4&prpSubType=1"
有兩個toPrpGroup參數,這樣看,如果有多個值的,都可以採用這個方法,即數據模型採用 List 數據類型,form的字段名稱不需要數組即可。