如何使用Razor和.NET Core将项目添加到ViewModel的列表中? [英] How to add an item to a list in a ViewModel using Razor and .NET Core?

查看:239
本文介绍了如何使用Razor和.NET Core将项目添加到ViewModel的列表中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这就是我的情况.

假设我有一个名为TheView.cshtml.的视图,TheView.cshtml有一个名为TheViewModel.cs的ViewModel.在TheViewModel.cs中,存在一个名为TheObjectList的对象(TheObject)的列表.

我有一个TheObject的编辑器模板,称为TheObject.cshtml.使用此编辑器模板,我可以简单地在TheObjectList@Html.EditorFor(model => model.TheObjectList)中显示所有项目.

但是,现在我想将对象动态添加到此列表中.我有一个AJAX函数,该函数调用一个简单的局部视图为用户提供空白行以添加新的"TheObject",但是,我动态添加的任何新的TheObject均不被视为原始TheObjectList的一部分./p>

这是因为原始TheObjectList中的每个项目都是基于其在原始列表中的索引创建的,并且具有特定的前缀,而每个新的动态TheObject的创建都没有前缀,因此Razor不会将其视为对象的一部分.列表.

有没有办法解决这个问题?

TheView.cshtml

@model Models.ViewModels.TheViewModel

<table id="Table">
    <tbody>
        @Html.EditorFor(m => m.TheObjectList);
    </tbody>
</table>

<button id="AddObject" type="button" class="btn btn-primary">Add Object</button>

TheViewModel.cs

public class TheViewModel
{
    public List<TheObject> TheObjectList { get; set; }
}

AddObject控制器方法

public IActionResult AddObject()
{
   return PartialView("_EmptyRow", new TheObject());
}

添加对象的AJAX方法

$('#AddObject').click(function () {
    $.ajax({
        url: 'AddObject',
        cache: false,
        success: function (data) {
            $('#Table > tbody').append(data);
        },
        error: function (a, b, c) {
            alert(a + " " + b + " " + c);
        }
     });
});

解决方案

基本上,您需要生成/返回标记,该标记看起来与编辑器模板为您的表单字段生成的标记相同,除了元素索引.您需要从客户端传递索引,该索引将成为表单字段名称的一部分.

假设您的编辑器模板如下所示,并且您的TheObject具有GroupName属性

@model TheObject
<div>
    @Html.HiddenFor(x => x.GroupName)
    @Html.TextBoxFor(s=>s.GroupName,new {@class="thingRow"})
</div>

现在,当使用当前代码渲染页面时,编辑器模板将生成类似这样的输入字段

<input class="thingRow" id="TheObjectList_0__GroupName" 
                           name="TheObjectList[0].GroupName" type="text" value="Something">

,其中0将替换为TheObjectList集合中各项的索引.

现在让我们说您已经在集合中有5个项目,因此,当用户单击添加按钮时,您想要生成与上面类似的标记,除了0将被5(替换为第六个项目).因此,让我们更新ajax调用以包括当前项数.

$('#AddObject').click(function () {
    var i = $(".thingRow").length;
    $.ajax({
        url: 'AddObject?index=' + i,
        success: function (data) {
            $('#Table > tbody').append(data);
        },
        error: function (a, b, c) {
            console.log(a, b, c);
        }
    });
});

这意味着,我们需要在操作方法中接受索引值.由于我们需要将此索引值从action方法传递到我们的视图以构建输入字段名称值,因此我在您的类中添加了一个名为Index

的属性

public ActionResult AddObject(int index)
{
    return PartialView("_EmptyRow", new TheObject { Index = index});
}

现在在您的_EmptyRow局部视图中,

@model TheObject
<input id="TheObjectList_@(Model.Index)__GroupName"class="thingRow" 
             name="TheObjectList[@(Model.Index)].GroupName"  type="text" value=""/>

现在,当您提交表单时,假设您将表格包含在表单中,则模型绑定将适用于这些动态添加的项目.

@model TheViewModel
@using (Html.BeginForm())
{   
    <table id="Table">
        <tbody>
            @Html.EditorFor(m => m.TheObjectList);
        </tbody>
    </table>
    <button id="AddObject" type="button" class="btn btn-primary">Add Object</button>
    <button type="submit" class="btn btn-primary">Save</button>
}

So here's my situation.

Let's say I have a view called TheView.cshtml. TheView.cshtml has a ViewModel called TheViewModel.cs. In TheViewModel.cs, resides a List of an object (TheObject) called TheObjectList.

I have an editor template for TheObject called TheObject.cshtml. Using this editor template, I can simply display all of the items in the TheObjectList with @Html.EditorFor(model => model.TheObjectList).

However, now I want to dynamically add objects to this list. I have a AJAX function which calls a simple partial view to give the user a blank row to add a new "TheObject", however, any new TheObject I add dynamically is not considered part of the original TheObjectList.

This is because each item in the original TheObjectList is created with a certain prefix based on its index in the original list, whereas each new dynamic TheObject is created without a prefix, thus Razor does not see it as part of the list.

Is there a way around this?

TheView.cshtml

@model Models.ViewModels.TheViewModel

<table id="Table">
    <tbody>
        @Html.EditorFor(m => m.TheObjectList);
    </tbody>
</table>

<button id="AddObject" type="button" class="btn btn-primary">Add Object</button>

TheViewModel.cs

public class TheViewModel
{
    public List<TheObject> TheObjectList { get; set; }
}

AddObject Controller Method

public IActionResult AddObject()
{
   return PartialView("_EmptyRow", new TheObject());
}

AJAX Method to Add Object

$('#AddObject').click(function () {
    $.ajax({
        url: 'AddObject',
        cache: false,
        success: function (data) {
            $('#Table > tbody').append(data);
        },
        error: function (a, b, c) {
            alert(a + " " + b + " " + c);
        }
     });
});

解决方案

You basically needs to generate/return markup which looks same as what the editor template generates for your form fields except for the element index . You need to pass the index from client side which will be a part of the form field name.

Let's assume your editor template looks like below and your TheObject has a GroupName property

@model TheObject
<div>
    @Html.HiddenFor(x => x.GroupName)
    @Html.TextBoxFor(s=>s.GroupName,new {@class="thingRow"})
</div>

Now when you render your page with your current code, Editor template will generate input fields like this

<input class="thingRow" id="TheObjectList_0__GroupName" 
                           name="TheObjectList[0].GroupName" type="text" value="Something">

where 0 will be replaced with the index of the items in your TheObjectList collection.

Now let's say you already have 5 items in the collection, So when user clicks add button, you want to generate markup like above except 0 will be replaced with 5(for the sixth item). So let's update the ajax call to include the current number of items.

$('#AddObject').click(function () {
    var i = $(".thingRow").length;
    $.ajax({
        url: 'AddObject?index=' + i,
        success: function (data) {
            $('#Table > tbody').append(data);
        },
        error: function (a, b, c) {
            console.log(a, b, c);
        }
    });
});

That means, we need to accept the index value in our action method. Since we need to pass this index value from action method to our view to build the input field name value, I added a property to your class called Index

public ActionResult AddObject(int index)
{
    return PartialView("_EmptyRow", new TheObject { Index = index});
}

Now in your _EmptyRow partial view,

@model TheObject
<input id="TheObjectList_@(Model.Index)__GroupName"class="thingRow" 
             name="TheObjectList[@(Model.Index)].GroupName"  type="text" value=""/>

Now when you submit the form, model binding will work for these dynamically added items, assuming you have your Table inside a form.

@model TheViewModel
@using (Html.BeginForm())
{   
    <table id="Table">
        <tbody>
            @Html.EditorFor(m => m.TheObjectList);
        </tbody>
    </table>
    <button id="AddObject" type="button" class="btn btn-primary">Add Object</button>
    <button type="submit" class="btn btn-primary">Save</button>
}

这篇关于如何使用Razor和.NET Core将项目添加到ViewModel的列表中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆