MVC的表單(form)綁定到數據模型上

參考網址:

列表類的綁定: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的字段名稱不需要數組即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章