Model Binding是Asp .net Mvc裡面用來處理表單送出(Form Post)資料自動轉成強型別的機制。
一般來說,如果用HtmlHelper
產生的html內容,在Post back的時候Model Binding基本上不會遇到什麼問題。
不過為了網站responsive更好,很多時候會希望Form Post是透過ajax來做。
這個時候依據不同做法,就很容易造成form post到asp .net mvc的時候Model Binding不到。
這篇將會建議不同情境的時候應該如何寫正確的Jquery Form post寫法,避免Model Binding不到的問題。
tag
標註每一個不同的情境。 三種情境建議做法 - TL;DR
基本上要form post的時候會遇到三種不同的情況:
- 想Post的內容是所有的Form欄位 - 換句話說只是要ajax post模擬一個
submit
的效果 - 想post的內容只是表單裡面幾個欄位,並非全部的欄位
- 想Post的內容包含檔案上傳
針對這三個不同情境,有幾個不同的jquery post方式建議:
- 想Post的內容是所有的Form欄位
只需要post的時候,
data
欄位傳入:$("#postForm").serialize()
即可。片段範例:
$.ajax({ type: "POST", url: "@Url.Action("JqueryPost")", data: $("#postForm").serialize() })
- 想post的內容只是表單裡面幾個欄位
- 組出最後要送出的javascript 物件
data
- 在 ajax 的
data
欄位值輸入:JSON.stringify(data)
- 在 ajax的
contentType
欄位值輸入:"application/json"
片段範例:
var data = []; data.push({ Title: $("input[name='[0].Title']").val(), Content: $("input[name='[0].Content']").val() }); data.push({ Title: $("input[name='[1].Title']").val(), Content: $("input[name='[1].Content']").val() }); $.ajax({ type: "POST", url: "@Url.Action("JqueryPost")", data: JSON.stringify(data), contentType: "application/json" })
- 組出最後要送出的javascript 物件
- 想post的內容包含檔案上傳
- 可以使用
FormData
,注意,只有支援Html 5的browser才能夠用,所以IE 10 以下就不用考慮了。- 用
Form
htmlelement 建立FormData
- 例如:var data = new FormData($("#postForm")[0]);
- 在 ajax 的
data
欄位值輸入第一步建立出來的data
- 在 ajax 的
processData
欄位值輸入:false
- 在 ajax 的
contentType
欄位值輸入:false
片段範例:
var data = new FormData($("#postForm")[0]); $.ajax({ type: "POST", url: "@Url.Action("JqueryPost")", data: data, processData: false, contentType: false })
- 用
如果對於為什麼這三種情境是這樣建議有興趣,請往下看.....
三種情境做法建議原因
依照不同的情境,jquery post的呼叫方式其實也會需要不同不然到asp .net mvc model binding的時候很容易失敗,會話很多時間在debug這些問題,以下將會對於3個情境的做法進一步說明。
想Post的內容是所有的Form欄位
一般來說,在建立Form表單的時候,撰寫上會使用HtmlHelper
,這種產生出來的html內容只要post上去asp .net mvc model binding基本上沒有什麼問題。
因此可以利用Form表單本身然後透過jquery序列化的方式作為送出的資料。
假設我們的Form表單的id是postForm
,那麼整個post方式就是:
$.ajax({ type: "POST", url: "@Url.Action("JqueryPost")", data: $("#postForm").serialize() })
換句話說其實就是用jquery模擬一般的postsubmit
。
想post的內容只是表單裡面幾個欄位
有時候要post的內容可能不全部在同一個Form
表單,或者可能有幾個不同地方的欄位組成,這個時候,第一種情境的序列化做法就不適合了。
這個時候可能會想說建立一個javascript 物件,然後直接post這個物件
。例如,假設後端要binding的model 有 Title和Content欄位:
var data = {}; data.Title = "a"; data.Content = "b"; $.ajax({ type: "POST", url: "@Url.Action("JqueryPost")", data: data })
這個會binding成功,因此可能想說都是這麼處理就好,但是,當要binding的物件比較複雜的時候,這個方式就會binding失敗。
舉例來說,假設我們有同樣的model結構,但是這個時候後台變成需要的是一個list,這個時候可能想說傳入array即可:
var data = []; data.push({ Title: "1", Content: "2" }); data.push({ Title: "2", Content: "4" }); $.ajax({ type: "POST", url: "@Url.Action("JqueryPost")", data: data })
但是這個會binding失敗,主要原因是因為預設jquery使用的是application/x-www-form-urlencoded
作為ContentType
- 這種方式的產生結構類似於querystring的那種串聯方式,因此在處理複雜結構 的時候產生出來的內容不符合asp .net mvc預設model binding的邏輯。
因此建議直接傳送json格式的內容,在處理複雜結構沒有什麼問題。
不過要使用json格式的資料就會需要:
- 用
JSON.stringfy()
把物件轉成json的字串樣子 - 把
ContentType
設定成為:application/json
- 告知mvc傳入的內容是json
因此整個範例變成:
var data = []; data.push({ Title: "1", Content: "2" }); data.push({ Title: "2", Content: "4" }); $.ajax({ type: "POST", url: "@Url.Action("JqueryPost")", data: SON.stringify(data), contentType: "application/json" })
- 範例程式碼,當object是單純的時候,直接post JavaScript 物件沒有問題:tag sample/jquery-simple-object-post
- 範例程式碼,當object是複雜物件的時候,直接post JavaScript物件有問題tag sample/jquery-complex-object-post-fail
- 範例程式碼,當object是複雜物件的時候,用json格式post - 建議方式tag sample/jquery-complex-object-post-sucess
想post的內容包含檔案上傳
當想要post上去的內容包含檔案上傳(input type="file")的時候,上述提到的2種做法都沒有辦法達成。
原因是因為檔案上傳要包含的資訊豐富很多,上述兩種方式都沒有辦法達到。
因此當需要post的內容包含檔案上傳,需要使用特殊的資料類型FormData
。
FormData
只有在支援Html 5的browser才有支援,因此IE 10 以下沒有辦法。 要使用FormData
非常的簡單,只需要在new的時候傳入Form的html element物件即可。
有了FormData
作為資料之後,還有兩個設定:
processData
要設定為false
避免jquery傳送的時候有額外做一些處理- 把
ContentType
設定為false
讓jquery決定送出的類型
整個的範例如下:
var data = new FormData($("#postForm")[0]); $.ajax({ type: "POST", url: "@Url.Action("JqueryPost")", data: data, processData: false, contentType: false })
結語
越來越多網站會要求直接使用ajax - 整個畫面不需要post給使用者感官沒有load那麼久。
希望透過這篇能夠提供一個Reference,當要用jquery ajax post的時候,asp .net mvc model binding不到的時候可以參考以下,避免在抓頭了。
沒有留言 :
張貼留言