以 ASP.NET 形式提交更改后的 FormData 以具有 ModelState 和重定向的正常行为

Submit changed FormData in ASP.NET form to have normal behavior with ModelState and redirections

我正在使用 APS.NET Core MVC (.NET 5.0) 开发网络应用程序。我有一个实体(服务),它有另一个实体(开放时间)的动态列表。所以一个服务可以有不同的开放时间,例如:

您可以根据需要设置不同的时间段。我不知道如何实施这种情况并寻找我找到的解决方案 and followed the 使其适应我的实体。稍微简化一下,代码如下:

模型(或视图模型):

public class Service
{
    public int Id { get; set; }
    [Required]
    public string Name { get; set; }
    [Required]
    public string Description { get; set; }
    public List<ServiceOpeningHours> OpeningHours { get; set; } = new List<ServiceOpeningHours>();
}

public class ServiceOpeningHours
{
    public TimeSpan From { get; set; }
    public TimeSpan To { get; set; }
}

Create.cshtml(查看):

@model MyWebApp.Services.Models.Service

...

<form asp-action="Create" name="createForm" id="createForm">
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="form-group">
            <label class="control-label">Name</label>
            <input asp-for="Name" class="form-control" />
            <span asp-validation-for="Name" class="text-danger"></span>
        </div>
        <div class="form-group">
            <label class="control-label">Description</label>
            <input asp-for="Description" class="form-control" />
            <span asp-validation-for="Description" class="text-danger"></span>
        </div>
        <fieldset>
            <legend>Opening Hours</legend>
            <div id="openingHoursContainer">
                @foreach (ServiceOpeningHours item in Model.OpeningHours)
                {
                    <partial name="_OpeningHourEditor" manifest model="item" />
                }
            </div>
        </fieldset>

        <div>
            <div class="form-group">
                <input id="addOpeningHourItem" type="button" value="Add Opening Hour" class="btn btn-primary" />
            </div>
            <div class="form-group">
                <input type="submit" id="submit" value="Create" class="btn btn-primary" />
            </div>
        </div>
    </form>

...

@section Scripts {
    $('#addOpeningHourItem').click(function (event) {
        event.preventDefault();
        $.ajax({
            async: true,
            data: $('#form').serialize(),
            type: 'POST',
            url: '/Services/AddBlankOpeningHour',
            success: function (partialView) {
                $('#openingHoursContainer').append(partialView);
            }
        });
    });
    $('#submit').click(function (event) {
        event.preventDefault();
        var formData = new FormData();

        formData.append("Name", $('input[name="Name"]').val());
        formData.append("Description", $('input[name="Description"]').val());

        $("input[name='From']").each(function (i) {
            var from = $(this).val();
            formData.append("OpeningHours[" + i + "].From", from);
        });
        $("input[name='To']").each(function (i) {
            var to = $(this).val();
            formData.append("OpeningHours[" + i + "].To", to);
        });

        formData.append("__RequestVerificationToken", $('form[name="createForm"] input[name="__RequestVerificationToken"]').val());
        
        $.ajax({
            method: 'POST',
            url: '/Services/Create',
            data: formData,
            processData: false,
            contentType: false,
            success: function (returnValue) {
                console.log('Success: ' + returnValue);
            }
        });
    });
}

_OpeningHourEditor.cshtml(开放时间项目的部分视图):

@model MyWebApp.Models.ServiceOpeningHours

<div class="row">
    <div class="col-md-6">
        <div class="form-group">
            <label class="control-label">From</label>
            <input asp-for="From" class="form-control" />
            <span asp-validation-for="From" class="text-danger"></span>
        </div>
    </div>
    <div class="col-md-6">
        <div class="form-group">
            <label class="control-label">To</label>
            <input asp-for="To" class="form-control" />
            <span asp-validation-for="To" class="text-danger"></span>
        </div>
    </div>
</div>

在 javascript 代码中创建了一个 FormData 并填充了所有字段,模型成功到达 Create 操作。

服务控制器:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create(Service service)
{
    if (ModelState.IsValid)
    {
        // Save data in data base...

        return this.RedirectToAction("Index");
    }
    return View(service);
}

[HttpPost]
public ActionResult AddBlankOpeningHour()
{
    return PartialView("_OpeningHourEditor", new ServiceOpeningHours());
}

使用此代码,当 Create 动作 returns 响应时,它到达 $.ajax()success 块,但这不会导致页面重新加载使用新数据。

我认为你不应该用 AJAX 来做。我应该如何拨打电话才能使一切正常?也就是说,如果 NameDescription 字段未填写,则应显示 ModelState 错误消息,如果一切顺利,则应将其重定向到 Index动作。

修改提交脚本以删除 ajax 并最初更改输入字段的名称,以便列表正确绑定到模型。

$('#submit').click(function (event) {
   // initially prevent form submit
   event.preventDefault();
   
   // loop through all input with name From, and change their name with index
   $("input[name='From']").each(function (i) {
      $(this).attr("name", "OpeningHours[" + i + "].From");
   });
   
   // loop through all input with name To, and change their name with index
   $("input[name='To']").each(function (i) {
      $(this).attr("name", "OpeningHours[" + i + "].To");
   });
   
   // submit the form
   $("#createForm").submit();
});