【问题标题】:A Partial View passing a collection using the Html.BeginCollectionItem helper使用 Html.BeginCollectionItem 帮助器传递集合的部分视图
【发布时间】:2017-03-25 04:09:05
【问题描述】:

我做了一个小项目来了解 Stephen Muecke 的答案:Submit same Partial View called multiple times data to controller?

几乎一切正常。 javascript 从局部视图中添加新字段,我可以通过控制器方法为局部视图插入的“临时”值来判断它们已绑定到模型。

但是,当我提交新字段时,AddRecord() 方法会引发异常,表明模型没有被传入(“对象引用未设置为对象的实例”)。

另外,当我查看页面源代码时,BeginCollectionItem 助手正在插入一个隐藏标记,因为它应该在显示预先存在的记录的主视图中的表周围插入一个隐藏标记,而不是在 javascript 添加的新字段周围。

我做错了什么?我对此很陌生,所以感谢您的耐心等待!

我的主要观点:

@model IEnumerable<DynamicForm.Models.CashRecipient>

@using (Html.BeginForm("AddDetail", "CashRecipients", FormMethod.Post))
{
    @Html.AntiForgeryToken()
    <div id="CSQGroup">
    </div>
}

<div>
    <input type="button" value="Add Field" id="addField" onclick="addFieldss()" />
</div>

<script>
    function addFieldss()
    {   
        //alert("ajax call");
        $.ajax({
            url: '@Url.Content("~/CashRecipients/RecipientForm")',
            type: 'GET',
            success:function(result) {
                //alert("Success");
                var newDiv = document.createElement("div"); 
                var newContent = document.createTextNode("Hi there and greetings!"); 
                newDiv.appendChild(newContent);  
                newDiv.innerHTML = result;
                var currentDiv = document.getElementById("div1");  
                document.getElementById("CSQGroup").appendChild(newDiv);
            },
            error: function(result) {
                alert("Failure");
            }
        });
    }
</script>

我的部分观点:

@model DynamicForm.Models.CashRecipient
@using HtmlHelpers.BeginCollectionItem

@using (Html.BeginCollectionItem("recipients"))
{
    <div class="editor-field">
        @Html.LabelFor(model => model.Id)
        @Html.LabelFor(model => model.cashAmount)
        @Html.TextBoxFor(model => model.cashAmount)
        @Html.LabelFor(model => model.recipientName)
        @Html.TextBoxFor(model => model.recipientName)
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Save" class="btn btn-default" />
        </div>
    </div>
}

我的模特:

public class CashRecipient
{
    public int Id { get; set; }
    public string cashAmount { get; set; }
    public string recipientName { get; set; }  
}

在我的控制器中:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AddDetail([Bind(Include = "Id,cashAmount,recpientName")] IEnumerable<CashRecipient> cashRecipient)
{
    if (ModelState.IsValid)
    {
        foreach (CashRecipient p in cashRecipient) {
            db.CashRecipients.Add(p);
        }
        db.SaveChanges();
        return RedirectToAction("Index");

    }

    return View(cashRecipient);
}

public ActionResult RecipientForm()
{
    var data = new CashRecipient();
    data.cashAmount = "temp";
    data.recipientName = "temp";
    return PartialView(data);
}

【问题讨论】:

  • 您不能将 Html.BeginCollectionItem() 应用于作为集合的模型 - 它应用于单个对象。而且您的视图甚至没有为 typeof CashRecipient 创建可编辑控件。代码中有许多错误,但不清楚您在这里尝试做什么。您是否想要一个可以动态添加(和/或删除)新 CashRecipient 并回发集合的表单?
  • 我正在尝试做 Brajesh 在您帮助他解决的问题中尝试做的完全相同的事情。我使用与他相同的 javascript 和大致相同的部分视图代码,除了使用 CashRecipient 而不是他的模型 AdminProductDetailModel。添加的每个控件都用于单个对象。模型本身不是一个集合。我认为 BeginCollectionItem 将多个控件的数据包装为一个集合......我可能误解了。你能帮我理解吗?
  • 在我的第一条评论中回答这个问题 :) 你为什么要使用 DisplayFor() - 它只是呈现文本,意味着没有什么是可编辑的
  • DisplayFor() 只是在显示现有项目的表中。与 Bajesh 的查询匹配的部分在下面,从 id 为 CSQGroup 的 div 开始。如果有帮助,您可以忽略整个表格,我可能不应该将其包括在内。是的,我想要一个可以动态添加新 CashRecipient 控件并回发多个 CashRecipient 实例的表单。
  • Bajesh 不存在与此问题相关的问题,因此请停止引用它。您是否还有不想编辑现有 CashRecipient 对象的特殊原因?

标签: javascript asp.net-mvc model-binding asp.net-mvc-partialview begincollectionitem


【解决方案1】:

首先创建一个视图模型来表示您要编辑的内容。我假设cashAmount 是货币值,因此应该是小数(根据需要添加其他验证和显示属性)

public class CashRecipientVM
{
    public int? ID { get; set; }
    public decimal Amount { get; set; }
    [Required(ErrorMessage = "Please enter the name of the recipient")]
    public string Recipient { get; set; }  
}

然后创建一个局部视图(比如)_Recipient.cshtml

@model CashRecipientVM
<div class="recipient">
    @using (Html.BeginCollectionItem("recipients"))
    {
        @Html.HiddenFor(m => m.ID, new { @class="id" })
        @Html.LabelFor(m => m.Recipient)
        @Html.TextBoxFor(m => m.Recipient)
        @Html.ValidationMesssageFor(m => m.Recipient)
        @Html.LabelFor(m => m.Amount)
        @Html.TextBoxFor(m => m.Amount)
        @Html.ValidationMesssageFor(m => m.Amount)
        <button type="button" class="delete">Delete</button>
    }
</div>

以及返回部分的方法

public PartialViewResult Recipient()
{
    return PartialView("_Recipient", new CashRecipientVM());
}

那么你的主要 GET 方法将是

public ActionResult Create()
{
    List<CashRecipientVM> model = new List<CashRecipientVM>();
    .... // add any existing objects that your editing
    return View(model);
}

它的视图将是

@model IEnumerable<CashRecipientVM>
@using (Html.BeginForm())
{
    <div id="recipients">
        foreach(var recipient in Model)
        {
            @Html.Partial("_Recipient", recipient)
        }
    </div>
    <button id="add" type="button">Add</button>
    <input type="submit" value="Save" />
}

并将包含一个脚本来为新的CashRecipientVM 添加 html

var url = '@Url.Action("Recipient")';
var form = $('form');
var recipients = $('#recipients');
$('#add').click(function() {
    $.get(url, function(response) {
        recipients.append(response);
        // Reparse the validator for client side validation
        form.data('validator', null);
        $.validator.unobtrusive.parse(form);
    });
});

以及删除项目的脚本

$('.delete').click(function() {
    var container = $(this).closest('.recipient');
    var id = container.find('.id').val();
    if (id) {
        // make ajax post to delete item
        $.post(yourDeleteUrl, { id: id }, function(result) {
            container.remove();
        }.fail(function (result) {
            // Oops, something went wrong (display error message?)
        }
    } else {
        // It never existed, so just remove the container
        container.remove();
    }
});

表格会发回给

public ActionResult Create(IEnumerable<CashRecipientVM> recipients)

【讨论】:

  • 如何删除?
  • @TravisTubbs,请参阅更新以从集合中删除项目(以及重新解析验证器以便您获得新项目的客户端验证
  • 谢谢斯蒂芬!这有助于我加载。
  • 如果我尝试在不添加任何新项目的情况下提交它,它会在 foreach 上崩溃。这是如何预防的?
  • @TravisTubbs,不确定你的意思,或者你得到了什么错误。由于这不是你的问题,我建议你问一个问题,显示你使用的代码和错误的详细信息(但最好的猜测是你没有将模型传递给视图,所以foreach(var recipient in Model) 抛出异常 - 你不能迭代null)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-17
  • 1970-01-01
  • 2017-10-25
  • 2012-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多