MVC5之表單集合資料自動繫結到物件屬性(集合)中

風靈使發表於2018-04-25
##前言 之前沒遇到過這個問題,在專案中遇到這個問題時想法挺好,按照流程走下去,結果事與願違,於是開始探索著解決方案,接下來我們來看看這個問題,早已經明瞭的童鞋請繞道,此文僅供未遇到的童鞋提供一種解決方案。

話題

首先我們來看看整個問題的出現,介紹一下問題的背景。

     public class Blog
    {
        public string BlogName { get; set; }
        public string BlogAddress { get; set; }
        public List<Article> Article { get; set; }
    }

    public class Article
    {
        public string ArticleIntr { get; set; }
        public string ArticleName { get; set; }
    }
上述給出兩個類,一個部落格包含多篇文章取集合屬性。
public ActionResult Test(Blog b)
        {
            var articleList = new List<Article>() { new Article() { ArticleIntr = "asp.net mvc", ArticleName = "mvc" }, new Article { ArticleIntr = "WebAPi", ArticleName = "WebAPi Authentication" } };
            var blog = new Blog() { BlogName = "xpy0928", BlogAddress = "CreateMyself", Article = articleList };           
            return View(blog);
        }

利用強型別檢視渲染到頁面

@using FormToObjList.Models
@model Blog
@{
    Layout = null;
}
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
<link href="~/Content/bootstrap.min.css" rel="stylesheet" />
<div style="width:700px;margin-left:200px;">
    <form action="test" method="post" enctype="multipart/form-data">
        <div style="float:left;">
            部落格地址:<input type="text" class="form-control" value="@Model.BlogAddress" /><br />
            部落格名稱:<input type="text" class="form-control" value="@Model.BlogName" /><br />
        </div>
        <br />

        <div style="float:right;">
            <table>
                <tr>
                    <th>序號</th>
                    <th>文章介紹</th>
                    <th>文章名稱</th>
                </tr>
                @{
                    var i = 0;
                    foreach (var article in Model.Article)
                    {
                        <tr>
                            <td>@(++i)</td>
                            <td><input type="text" class="form-control" value="@article.ArticleIntr" /></td>
                            <td><input type="text" class="form-control" value="@article.ArticleName" /></td>
                        </tr>
                    }
                }
            </table>
        </div>
        <div style="clear:both;float:right;">
            <button class="btn btn-primary" type="submit">提交</button>
        </div>
    </form>
</div>

到這裡我們需要實現的是點選提交後將頁面上所有的資料都新增到後臺【Blog b】屬性,著重強調的是獲取到b中屬性Article要有兩條我們渲染的資料。

我們看看演示結果:
這裡寫圖片描述

我們可以看到居然都為空,彆著急,此時都會想到既然要獲取到值,則文字的name屬性要和類中的屬性一一對應才是,說完就開幹。

  部落格地址:<input type="text" name="BlogAddress" class="form-control" value="@Model.BlogAddress" /><br />
  部落格名稱:<input type="text" name="BlogName"    class="form-control" value="@Model.BlogName" /><br />



 <td><input type="text" name="ArticleIntr" class="form-control" value="@article.ArticleIntr" /></td>
 <td><input type="text" name="ArticleName" class="form-control" value="@article.ArticleName" /></td>

進行如上設定後我們再來看看結果:
這裡寫圖片描述

恩,有點小憂傷,對於Article這個集合屬性資料並未新增到其中去,這個就是我們需要解決的問題。到了這裡我尋思著是不是不能用html標籤,需要用mvc自己來渲染成html標籤才行呢?也就是說利用【 @Html.TextBoxFor() 】來進行渲染,此時是個集合,則只能用for迴圈來進行遍歷,於是乎將資料渲染時修改成下面的這個樣子。

               @{
                    var j = 0;
                    for (var i = 0; i < Model.Article.Count; i++)
                    {
                        <tr>
                            <td>@(++j)</td>
                            <td>@Html.TextBoxFor(a => a.Article[i].ArticleIntr, new { @class="form-control"})</td>
                            <td>@Html.TextBoxFor(a => a.Article[i].ArticleName, new { @class="form-control"})</td>
                        </tr>
                    }
                }

我們繼續看看結果:
這裡寫圖片描述

好了,我們終於得到我們想要的結果了,你是不是覺得就這麼愉快的結束了呢?

實際需求

在專案中我們需要做的是新增,同時在頁面開始時有幾個預設的文字框且還需要動態新增行,這個時候我們又該如何做呢?我們一起來看看。

               @{
                    if (Model.Article != null)
                    {
                        var j = 0;
                        for (var i = 0; i < Model.Article.Count; i++)
                        {
                            <tr>
                                <td>@(++j)</td>
                                <td>@Html.TextBoxFor(a => a.Article[i].ArticleIntr, new { @class = "form-control" })</td>
                                <td>@Html.TextBoxFor(a => a.Article[i].ArticleName, new { @class = "form-control" })</td>
                            </tr>
                        }
                    }
                    else 
                    {

                    }
                }

如果預設沒有值時,我們則需要自己新增預設的文字,此時該如何新增,我們想想當直接利用htm文字標籤和利用Html.TextBoxFor渲染的效果有何不同?看看如下:

//Html標籤
<input type="text" name="ArticleIntr" class="form-control" value="WebAPi">


//Html.TextBoxFor()
<input class="form-control" id="Article_1__ArticleIntr" name="Article[1].ArticleIntr" type="text" value="Angular">

這個時候我們恍然大悟,既然是集合那麼name則是取到對應的索引值,我們照樣畫葫蘆,於是我們修改成如下:

                @{
                    if (Model.Article != null)
                    {
                        var j = 0;
                        for (var i = 0; i < Model.Article.Count; i++)
                        {
                            <tr>
                                <td>@(++j)</td>
                                <td>@Html.TextBoxFor(a => a.Article[i].ArticleIntr, new { @class = "form-control" })</td>
                                <td>@Html.TextBoxFor(a => a.Article[i].ArticleName, new { @class = "form-control" })</td>
                            </tr>
                        }
                    }
                    else
                    {
                        var j = 0;
                        for (var i = 0; i < 3; i++)
                        {
                            <tr id="trs">
                                <td>@(++j)</td>
                                <td><input type="text" name="Article[@i].ArticleIntr" class="form-control" /></td>
                                <td><input type="text" name="Article[@i].ArticleName" class="form-control" /></td>
                            </tr>
                        }
                    }
                }

動態新增時的操作:

        $("#btnAdd").on("click", function () {
            var trLen = $("#tb tr[id='trs']").length;
            var $lastTr = $("#tb tr[id='trs']").last();
            var tr = "<tr id='trs'>";
            tr += "<td>" + (trLen + 1) + "</td>";
            tr += "<td><input type='text' name='Article[" + trLen + "].ArticleIntr' class='form-control' /></td>";
            tr += "<td><input type='text' name='Article[" + trLen + "].ArticleName' class='form-control' /></td>";
            tr += "</tr>";
            $(tr).insertAfter($lastTr);
        });

完整效果如下:
這裡寫圖片描述

至此我們的需求才算結束。

總結

專案中渲染檢視都是採用MVC中Razor渲染的方式,所以在做的時候也是跟著專案同樣的風格去做,做的時候才發現這個問題並解決了下,學習,學習,可能還有其他解決方案,這也算是其中一種吧。

相關文章