【问题标题】:How can I post multiple users in one form?如何以一种形式发布多个用户?
【发布时间】:2021-12-07 00:49:14
【问题描述】:

我想注册未知数量的用户,并希望避免为每个用户单独提交表单。

我想我已经找到了可以添加和删除用户行的视图(感谢this 文章)。

但我似乎无法让它绑定到控制器的 POST 方法。 Users 正在返回 null

更新

在控制器方法中添加[Bind("Users")] 修复了null 问题!现在我正在与行的不雅作斗争。

更新 2

解决了!添加<input type="hidden" name="Users.Index" value="{some unique value}" /> 解决了索引问题。我现在可以认为索引是非顺序的,不用担心维护顺序。我已经用时间戳替换了下面答案中介绍的lastIndex。它可以是任何随机数,只要它对表单中的每一行都是唯一的。

这就是我现在拥有的:

模型

public class ApplicationUserViewModel
{
    public string Email { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class BatchUserRegistrationViewModel
{
    public List<ApplicationUserViewModel> Users { get; set; }
}

创建视图

@model NameSpace.Models.BatchUserRegistrationViewModel

<form asp-action="RegisterManyUsers">
    @if (Model.Users != null)
    {
        // This part is for when the ModelState is not valid, and POST redirects back to the view.
        // I want the submitted form data to persist.
        for (int i = 0; i < Model.Users.Count; i++)
        {
            <div id="inputFormRow">
                <div class="input-group mb-3">
                    <input type="hidden" name="Users.Index" value="@i" />
                    <input type="text" name="users[@i].Email">
                    <input type="text" name="users[@i].FirstName>
                    <input type="text" name="users[@i].LastName">
                    <div class="input-group-append">
                        <button id="removeRow" type="button">
                            (-) Remove row
                        </button>
                    </div>
                </div>
            </div>
        }
    }
    else
    {
        // This part is for a new, blank form:
        <div id="inputFormRow">
            <div class="input-group mb-3">
                <input type="hidden" name="Users.Index" value="0" />
                <input type="text" name="users[0].Email">
                <input type="text" name="users[0].FirstName">
                <input type="text" name="users[0].LastName">
                <div class="input-group-append">
                    <button id="removeRow" type="button">
                        (-) Remove row
                    </button>
                </div>
            </div>
        </div>
    }
    <div id="newRow"></div>
    <p>
        <button id="addRow" type="button">
            (+) Add row
        </button>
    </p>
    <p>
        <button type="submit">(v) Register users</button>
    </p>
</form>

客户端脚本

<script>
    // add row
    $("#addRow").click(function () {
        let ts = $.now();
        var html = '';
        html += '<div id="inputFormRow">';
        html += '    <div class="input-group mb-3">';
        html += '        <input type="hidden" name="Users.Index" value="' + ts + '" />';
        html += '        <input type="text" name="users[' + ts + '].Email">';
        html += '        <input type="text" name="users[' + ts + '].FirstName">';
        html += '        <input type="text" name="users[' + ts + '].LastName">';
        html += '        <div class="input-group-append">';
        html += '            <button id="removeRow" type="button">';
        html += '                (-) Remove row';
        html += '            </button>';
        html += '        </div>';
        html += '    </div>';
        html += '</div>';
        $('#newRow').append(html);
    });

    // remove row
    $(document).on('click', '#removeRow', function () {
        $(this).closest('#inputFormRow').remove();
    });
</script>

控制器 POST 方法

public async Task<IActionResult> RegisterManyUsers([Bind("Users")] BatchUserRegistrationViewModel BatchReg)
{
    if (ModelState.IsValid)
    {
        if (BatchReg.Users != null)
        {
            List<ApplicationUser> dbUsers = new();
            foreach (ApplicationUserViewModel user in BatchReg.Users)
            {
                dbUsers.Add(new ApplicationUser {
                    Email = user.Email,
                    FirstName = user.FirstName,
                    LastName = user.LastName
                });
            }
            db.AddRange(dbUsers);
            await db.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
    }
    return View(BatchReg);
}

【问题讨论】:

  • 你添加的行名不正确,应该是users[0].Email
  • 可以通过在脚本中定义一个全局变量来实现

标签: c# asp.net-core-mvc model-binding


【解决方案1】:

试试这个:

<script>
let lastIndex= 0 ;
// add row
$("#addRow").click(function () {
    var html = '';
    html += '<div id="inputFormRow">';
    html += '    <div class="input-group mb-3">';
    html += '        <input type="text" name="users['+lastIndex+'].Email">';
    html += '        <input type="text" name="users['+lastIndex+'].FirstName">';
    html += '        <input type="text" name="users['+lastIndex+'].LastName">';
    html += '        <div class="input-group-append">';
    html += '            <button id="removeRow" type="button">';
    html += '                (-) Remove row';
    html += '            </button>';
    html += '        </div>';
    html += '    </div>';
    html += '</div>';
    lastIndex=lastIndex+1;
    $('#newRow').append(html);
});

// remove row
$(document).on('click', '#removeRow', function () {
    lastIndex=lastIndex-1;
    $(this).closest('#inputFormRow').remove();
});

【讨论】:

  • 嗯,你可能是对的,但似乎这与 OP 的要求无关。
  • @steve 好吧,我认为逻辑没问题,只是由于索引错误而发送 null
  • OP 抱怨 POST 整个模型为 null 而不是一行。 IE 此处您要修复的块之前的块。
  • @fatemehyadollahzadeh 这几乎可以工作了。用户现在存储在数据库中。但是 DOM 中的 index[0] 和脚本创建的不匹配之间存在冲突或不匹配。如果我删除第一行然后提交一些行的列表,则控制器不会接收到第一行。如果我不删除第一行而只提交那一行,它就会被控制器接收。
  • @Steve 我修复了null 问题。查看更新的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多