【问题标题】:TextBoxFor with List<object> always returns null to controller带有 List<object> 的 TextBoxFor 始终向控制器返回 null
【发布时间】:2017-08-13 09:39:56
【问题描述】:

我正在尝试添加多行输入,或者在脚本的帮助下添加多个输入以将它们作为 List 提交给控制器。如果我使用 TextBoxFor,我会在此列表的控制器中得到 count=0,如果我使用 EditorFor,则为 null。 正如我目前所了解的那样,我只是在形成一个对象,而不是一个对象列表,这就是为什么它是 null 或 count=0 ...但是如何正确地做到这一点?

查看:

<div>
    @using (Html.BeginForm())
    {
        //other form-groups

        <div class="form-group">
            @Html.LabelFor(m => @Model.MediaRSSURL)
            @Html.TextBoxFor(m => @Model.MediaRSSURL, "URL/URL", new {htmlAttributes = new {@class = "form-control"}})
        </div>

        <input type="submit" value="Submit"/>
    }
</div>

带列表的类:

public class Media
{
    //other properties

    public List<URL> MediaRSSURL { get; set; }
}

对象的类:

    public class URL
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string strURL { get; set; }
    public int MediaId { get; set; }
    public Media Media { get; set; }

}

EditorTemplate:

位于 Shared/EditorTemplates/URL

@model Domain.Entities.URL

<div class="form-group">
    @Html.TextBoxFor(m => Model.strURL, new {htmlAttributes = new {@class = "form-control"}})
    @Html.HiddenFor(m => Model.Id)
    @Html.HiddenFor(m => Model.MediaId)
</div>

控制器 POST 方法:

        [System.Web.Mvc.HttpPost]
    public RedirectToRouteResult AddMedia([FromBody] Media media)
    {

        if (ModelState.IsValid)
        {
            _iMediaRepository.SaveMedia(media);
        }

        return RedirectToAction("GetAllMedia");
    }

控制器 GET 方法:

        [System.Web.Mvc.HttpGet]
    public ViewResult AddMedia()
    {

        return View();
    }

更新:


填充集合并将模型传递给视图:

        [System.Web.Mvc.HttpGet]
    public ViewResult AddMedia()
    {
        var model = new Media();
        var newUrl = new URL();
        model.MediaRSSURL = new List<URL>();
        model.MediaRSSURL.Add(newUrl);

        return View(model);
    }

更改了编辑器模板:

    @model IEnumerable<Domain.Entities.URL>

<div class="form-group">

    @foreach (URL url in Model)
    {
        @Html.EditorFor(m => url.strURL, new { htmlAttributes = new { @class = "form-control" } })
        @Html.HiddenFor(m => url.Id)
        @Html.HiddenFor(m => url.MediaId)
        @Html.HiddenFor(m => url.Media)
    }

</div>

【问题讨论】:

  • 您不能将文本框绑定到复杂对象的集合。你有一个EditorTemplate,所以使用@Html.EditorFor(m =&gt;m.MediaRSSURL),它将根据模板为你的集合中的每个对象生成html。
  • @StephenMuecke 我已经尝试过了,如果我使用 EdirorFor,我会得到 null
  • 那么这意味着您的收藏中没有任何物品!展示您的 GET 方法以及您如何填充集合并将其传递给视图
  • @StephenMuecke 我已经更新了帖子。我的 GET 方法很简单——我只返回 View();我需要将 List 作为模型传递给 View 吗?
  • return View(); 不会将模型传递给视图,因此 MediaRSSURLnull。因此没有要显示的项目

标签: c# asp.net-mvc


【解决方案1】:

解决方案:

感谢@stephen-muecke 和他的建议,我成功了!

查看页面:

一个很好的article 了解如何处理复杂类型。还有来自上面链接的article,它帮助我找出了我的一个错误。 为了动态添加输入,我使用了来自this post(选项2)的技术

    @model Media

<div>
    @using (Html.BeginForm())
    {      
        <div class="form-group">
            @Html.LabelFor(m => m.MediaRSSURL)

            <div id="URLContainer">
                @Html.EditorFor(m => m.MediaRSSURL)
            </div>
            <div id="URLfield" style="display: none">
                <!--You need to look in HTML how is your input formed and just copy it to make a fake input. Then replace the numbers in attributes by hashtag. For example name="MediaRSSURL[0].strURL" to name="MediaRSSURL[#].strURL"-->
                <div class="form-group">
                    <input class="form-control text-box single-line" id="MediaRSSURL_#__strURL" name="MediaRSSURL[#].strURL" type="text" value="" data-cip-id="MediaRSSURL_#__strURL">
                </div>

            </div>

        </div>
        <div>
            <input type="button" value="Add URL" id="addURL" onclick="addURLs()"/>
        </div>

        <input type="submit" value="Submit"/>
    }
</div>

@section scripts
{

    <script>
        //On click you clone the fake input and replace all # signs to a number from counter and append new input to your container
        var counter = 1;
        $('#addURL')
            .click(function() {
                var clone = $('#URLfield').clone();
                // Update the indexer and Index value of the clone
                clone.html($(clone).html().replace(/#/g, counter));
                clone.html($(clone).html().replace(/"%"/g, '"' + counter + '"'));
                $('#URLContainer').append(clone.html());
                counter++;
            });

    </script>
}

带列表的类:

 public class Media
{
    // Other properties

    public List<URL> MediaRSSURL { get; set; }
}

对象的类:

没有变化

编辑器模板:

这是我犯了一个错误并花了几个小时来理解它的地方: 首先将模板放在 Views/Shared/EditorTemplates/URL/URL 我需要它有这样的位置:Views/NameOfYourController/EditorTemplates/URL 在我更改了编辑器模板的位置之后,像 name="MediaRSSURL[0].strURL" 这样的属性开始在 HTML 中生成,让我知道最终来自输入的数据将进入一个列表。此外,我不必在 EditorFor 和模型中(通过 [UIHint("URL")] )指定模板的地址 - 没有这些也可以工作。

   @model Domain.Entities.URL

<div class="form-group">
        @Html.EditorFor(m => m.strURL, new { htmlAttributes = new { @class = "form-control" } })
</div>

控制器 POST 方法:

没有重大变化。不需要 [FromBody],但它在此时没有任何影响。

控制器 GET 方法:

这是我犯第二个错误的地方——我首先没有将模型传递给 View。 我还初始化了 a) 模型 b) 它的 List c) 和 object

   [System.Web.Mvc.HttpGet]
public ViewResult AddMedia()
{
    URL newUrl1 = new URL();
    var model = new Media();
    model.MediaRSSURL = new List<URL>();
    model.MediaRSSURL.Add(newUrl1);

    return View(model);
}

【讨论】:

    【解决方案2】:

    你不能这样工作。因为 MediaRSSURL 作为列表返回,但您将其用作文本框。如果您可以将其用作列表框,它将起作用,或者您应该将其作为字符串返回。所以,这样

    @model List<Domain.Entities.URL>
    

    @foreach(模型中的项目)

    @Html.TextBoxFor(m => item.strURL, new {htmlAttributes = new {@class= "form-control"}}) @Html.HiddenFor(m => item.Id) @Html.HiddenFor(m => item.MediaId)

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-20
    • 1970-01-01
    • 2016-05-31
    • 2015-08-15
    • 2012-03-18
    • 2016-11-04
    相关资源
    最近更新 更多