ASP.Net MVC實作資料列裡面的Input欄位資料傳遞到Controller的方法

工作實務中很常遇到這種情境,資料列裡面的Input資料post到Controller的方法。這邊演示一下如何處理處理這種常見的問題。

範例說明:
通常會是像類似下圖的功能,先輸入查詢條件後點選查詢,會帶出資料列,資料列中可能會有Input可以輸入資料,輸入完畢後按下最下方的Submit就可以post資料到後端進行db資料異動。

通常資料列裡面的資料都是由ModelView搭配@Html.TextBoxFor搭配Foreach所組成,透過TextBoxFor所產生的Input預設的name會跟ModelView的結構一樣。
以上面的範例來說:
Razor語法大概是這樣:
data_index是一個序列數字,由0開始。由於L_Item在ViewModel裡面的型別是List,所以name這樣命名的話到時候才能與Model Binding起來。

<td colspan="5" height="30" class="borderless-left">
	<label class="margin-r-5">@Html.Translation("Problem"):</label>
    @Html.TextAreaFor(m => m.L_Item[data_index].Remote_Problem_Desc)
</td>

Render 出來的HTML會長這樣

<textarea class="Font_Small" cols="80" id="L_Item_0__Remote_Problem_Desc" name="L_Item[0].Remote_Problem_Desc" rows="2"></textarea>

可以看但Render出來的Input name為L_Itemp[0].Remote_Problem_Desc,這樣的命名格式已經可以跟ViewModel的L_Item進行Binding了。

送出資料的方式,由於還須要在前端Javascript做一些資料處理,所以我是採用ajax來post資料到後端,下面我們來看一下JS處理的部分。

            var check = false;
            var illegalCharacterCheck = false;
            var get_input_data = false;
            var param = {}

            //get rowdata input value
            var new_index = -1;
            $("#form_list :input").each(function () {
                if ($(this).hasClass('transport_info')) {
                    get_input_data = true;
                }

                if (this.type && this.type == "checkbox" && $(this).hasClass("check_flag")) {
                    if (this.checked) {
                        new_index += 1;
                        check = true;
                        get_input_data = true;
                    }
                    else {
                        get_input_data = false;
                    }
                }
                else {
                    if (get_input_data) {
                        @*由0開始,重新設定input name 的index*@
                        var idx_1 = this.name.indexOf('[');
                        var idx_2 = this.name.indexOf(']');
                        if (idx_1 > 0 && idx_2 > 0) {
                            this.name = this.name.substring(0, idx_1 + 1) + new_index + this.name.substring(idx_2, this.name.length);
                        }

                        if (param[this.name] == null) {
                            param[this.name] = [];
                        }

                        if (this.name.endsWith("Remark") || this.name.endsWith("Desc"))
                        {
                            var encode_value = $("<div>").text(this.value).html();
                            param[this.name].push(encode_value);
                        }
                        else
                        {
                            if (this.value.includes("<") || this.value.includes(">")) {
                                illegalCharacterCheck = true;
                            }
                            param[this.name].push(this.value);
                        }
                    }
                }
            })

            if (!check) {
                msg("Please choose the order first.")
                return;
            }
            if (illegalCharacterCheck) {
                msg("'<' and '>' are illegal characters.")
                return;
            }

            var url = "@Url.Action(SaveActionName, ControllerName,new {Area= AreaName })";

            //读取数据
            $.post(url, param, function (data) {
                showDialog(data.msg, 'notice', 'Notice', null, 1,
                    function () {
                        if (!isNullOrEmpty(data['status']) && data['status'] != 1) {
                            $('#Searchy').click();
                        }
                    });
            }, "json")
            .done(function () {

            })
            .fail(function (o) {
                var error = isNullOrEmpty(o.msg) ? "" : o.msg;
                msg("System error, please contact IT. " + error);
            }); 

大致整理一下JS處理了什麼事情:

1.先透過JQuery Selector$("#form_list :input")找出表單form_list底下的所有input,如果遇到checkbox的話,我們就要把在這個checkbox之後,下一個checkbox之前的所有input的值放到param變數裡面。

2.如果是跳著勾選checkbox的話,會導致L_Item的data_index就不會由0開始了。舉例來說,如果我們勾選的是第1.3.5列資料的話,就只會有L_Item[0] & L_Item[2] & L_Item[4]的資料,如果直接這樣把資料post到後台的話,到時Action的參數會對應不起來,List的Index一定要從0.1.2.3…..這樣序列下去才可以。

3.碰到input name的結尾為Remark或是Desc的欄位的話,由於這兩個欄位可以允許輸入這兩個特殊符號,所以要把"<"跟">"這種特殊符號透過$("<div>").text(this.value).html()把特殊符號進行編碼。如果沒有加上沒有加上$("<div>").text(this.value).html()的話,帶有"<"跟">"的輸入值post到後端時,因為安全性而被擋下(如下圖所示),譬如說你輸入<test>會自己幫你就會發生錯誤。

param變數內容

有加上$("<div>").text(this.value).html()的話,你輸入<test>就會變成一個"&lt;test&gt;"字串,而不會被ASP.Net視為HTML標籤

param變數內容

js處理完資料後,就可以把param這個變數直接透過ajax傳給後端了,後端Action的ViewModel參數會依照傳進來的物件自己去找對應的成員名稱去做Binding,也就是說如果你的HTML的name取的跟ViewModel裡面的成員的名稱不一樣的會,是Binding不到的喔。Model Binding的結果如下:

ViewModel

成功把資料送到後端後,就看要怎麼做DB異動啦~


 

ref:
如果要將值寫進html中就必須做HTML encode,jQuery可以簡單的做到encode與decode的效果