工作實務中很常遇到這種情境,資料列裡面的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>會自己幫你就會發生錯誤。
有加上$("<div>").text(this.value).html()的話,你輸入<test>就會變成一個"<test>"字串,而不會被ASP.Net視為HTML標籤
js處理完資料後,就可以把param這個變數直接透過ajax傳給後端了,後端Action的ViewModel參數會依照傳進來的物件自己去找對應的成員名稱去做Binding,也就是說如果你的HTML的name取的跟ViewModel裡面的成員的名稱不一樣的會,是Binding不到的喔。Model Binding的結果如下:
成功把資料送到後端後,就看要怎麼做DB異動啦~
ref:
如果要將值寫進html中就必須做HTML encode,jQuery可以簡單的做到encode與decode的效果