web-dev-qa-db-ja.com

Html.BeginCollectionItemヘルパーを使用してコレクションを渡す部分ビュー

ここでスティーブンミューケからの答えを理解するために小さなプロジェクトを作成しました: 複数回のデータと呼ばれる同じ部分ビューをコントローラーに送信しますか?

ほとんどすべてが機能します。 javascriptは、パーシャルビューから新しいフィールドを追加します。パーシャルビューのコントローラーメソッドによって挿入された「temp」値によって、それらがモデルにバインドされていることがわかります。

ただし、新しいフィールドを送信すると、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);
}
15
Robert M.

まず、編集したいものを表すビューモデルを作成することから始めます。 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)
24
user3559349