【问题标题】:Modal form validation in asp.net core 2.1 and Razor pagesasp.net core 2.1 和 Razor 页面中的模态表单验证
【发布时间】:2018-12-05 15:17:29
【问题描述】:

我有一个 Details.cshtml 页面,其中显示了客户的详细信息以及 customer.sites 的链接列表。在页面上,我创建了一个按钮来添加一个新网站,该按钮会打开一个引导模式,其中包含用于进入新网站的表单。

我遇到的问题是验证。如果表单无效,则页面会重新加载,但模式会再次隐藏,这意味着除非用户再次单击添加站点按钮,否则看不到 asp-validation-for 文本。有什么办法可以在 ModelState.IsValid 无效时自动保持打开状态?

details.cshtml 页面

@page "{id:int?}"
@model ServiceManager.Pages.Customers.DetailsModel

@{
    ViewData["Title"] = "Details";
}
<h2>@Html.DisplayFor(model => model.Customer.Name)</h2>
<hr />
<!-- Modal -->
<div class="modal fade" tabindex="-1" role="dialog" aria-hidden="true" id="createSiteModal">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">Add New Customer Site</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            <div class="modal-body">
                <form method="post">
                    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
                    <div class="form-group">
                        <label asp-for="Site.Description" class="control-label"></label>
                        <input asp-for="Site.Description" class="form-control" />
                        <span asp-validation-for="Site.Description" class="text-danger"></span>
                    </div>
                    <div class="form-group">
                        <label asp-for="Site.AddressLine" class="control-label"></label>
                        <textarea asp-for="Site.AddressLine" class="form-control"></textarea>
                        <span asp-validation-for="Site.AddressLine" class="text-danger"></span>
                    </div>
                    <div class="form-group">
                        <label asp-for="Site.City" class="control-label"></label>
                        <input asp-for="Site.City" class="form-control" />
                        <span asp-validation-for="Site.City" class="text-danger"></span>
                    </div>
                    <div class="form-group">
                        <label asp-for="Site.County" class="control-label"></label>
                        <input asp-for="Site.County" class="form-control" />
                        <span asp-validation-for="Site.County" class="text-danger"></span>
                    </div>
                    <div class="form-group">
                        <label asp-for="Site.Postcode" class="control-label"></label>
                        <input asp-for="Site.Postcode" class="form-control" />
                        <span asp-validation-for="Site.Postcode" class="text-danger"></span>
                    </div>
                    <div class="form-group">
                        <label asp-for="Site.Country" class="control-label"></label>
                        <input asp-for="Site.Country" class="form-control" />
                        <span asp-validation-for="Site.Country" class="text-danger"></span>
                    </div>
                    <div class="form-group">
                        <label asp-for="Site.Telephone" class="control-label"></label>
                        <input asp-for="Site.Telephone" class="form-control" />
                        <span asp-validation-for="Site.Telephone" class="text-danger"></span>
                    </div>
                    <div class="form-group">
                        <label asp-for="Site.Fax" class="control-label"></label>
                        <input asp-for="Site.Fax" class="form-control" />
                        <span asp-validation-for="Site.Fax" class="text-danger"></span>
                    </div>
                    <div class="form-group">
                        <input asp-for="Site.CommercialID" class="form-control" value="3" />
                    </div>
                    <div class="form-group">
                        <input type="button" value="Cancel" class="btn btn-danger" data-dismiss="modal" />
                        <input type="submit" value="Create" class="btn btn-success" />
                    </div>
                </form>
            </div>
        </div>
    </div>
</div>
<div class="btn-group" role="group">
    <a class="btn btn-light" data-toggle="tooltip" data-placement="top" data-delay="200" title="Back to Customer List" asp-page="./Index">
        <span class="fas fa-arrow-left fa-1x" style="color:#007bff"></span>
    </a>
    @if (Model.Customer.CustomerType == "Domestic")
    {
        <a class="btn btn-light" asp-page="./EditDom" asp-route-id="@Model.Customer.ID" data-toggle="tooltip" data-placement="top" data-delay="200" title="Edit Customer">
            <span class="fas fa-user-edit fa-1x" style="color:#0c0cbe"></span>
        </a>
    }
    else
    {
        <a class="btn btn-light" asp-page="./Edit" asp-route-id="@Model.Customer.ID" data-toggle="tooltip" data-placement="top" data-delay="200" title="Edit Customer">
            <span class="fas fa-user-edit fa-1x" style="color:#0c0cbe"></span>
        </a>
    }
        <a class="btn btn-light" asp-page="./Delete" asp-route-id="@Model.Customer.ID" data-toggle="tooltip" data-placement="top" data-delay="200" title="Delete Customer">
            <span class="fas fa-user-times fa-1x" style="color:#b01111"></span>
        </a>
</div>
<div class="row">
    <div class="col-lg-4">
        <div class="card border-info mb-3">
            <h5 class="card-header bg-info text-white">Customer Details</h5>
            <div class="card-body">
                <dl class="row">
                    <dt class="col-5">
                        @Html.DisplayNameFor(model => model.Customer.AccountRef)
                    </dt>
                    <dd class="col-7">
                        @Html.DisplayFor(model => model.Customer.AccountRef)
                    </dd>
                    <dt class="col-5">
                        @Html.DisplayNameFor(model => model.Customer.ContactDate)
                    </dt>
                    <dd class="col-7">
                        @Html.DisplayFor(model => model.Customer.ContactDate)
                    </dd>
                    <dt class="col-5">
                        @Html.DisplayNameFor(model => model.Customer.Active)
                    </dt>
                    <dd class="col-7">
                        @Html.DisplayFor(model => model.Customer.Active)
                    </dd>
                </dl>
            </div>
        </div>
    </div>
    <div class="col-lg-4">
        <div class="card border-info mb-3">
            <h5 class="card-header bg-info text-white">Customer Sites</h5>
            <table class="table table-hover fixed-table">
                <tr>
                    <th>Description</th>
                    <th>Location</th>
                    <th>Telephone</th>
                </tr>
                @foreach (var item in Model.Customer.Sites)
                {
                    <tr>
                        <td>
                            @Html.DisplayFor(modelItem => item.Description)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.City)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.Telephone)
                        </td>
                        <td>
                            <a class="rowlink" asp-page="/Sites/Details" asp-route-id="@item.ID"><i class="fa fa-chevron-right"></i></a>
                        </td>
                    </tr>
                }
            </table>
            <div class="card-footer">
                <!-- Button trigger modal -->
                <button class="btn btn-link float-right" data-toggle="modal" data-target="#createSiteModal">
                    <span class="fa-stack fa-lg">
                        <i class="fas fa-circle fa-stack-2x" style="color:tomato"></i>
                        <i class="fas fa-stack-1x fa-inverse">+</i>
                    </span>
                </button>
                <div class="clearfix"></div>
            </div>
        </div>
    </div>
</div>

Details.cshtml.cs 页面

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using ServiceManager.Models;

namespace ServiceManager.Pages.Customers
{
    public class DetailsModel : PageModel
    {
        private readonly CompanyContext _context;

        public DetailsModel(CompanyContext context)
        {
            _context = context;
        }

        public Commercial Customer { get; set; }


        public async Task<IActionResult> OnGetAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            Customer = await _context.Commercial
                .Include(c => c.Sites)
                .Include(c => c.Contacts)
                .FirstOrDefaultAsync(m => m.ID == id);

            if (Customer == null)
            {
                return NotFound();
            }
            return Page();
        }

        [BindProperty]
        public Address Site { get; set; }

        public async Task<IActionResult> OnPostAsync(int? id)
        {

            if (!ModelState.IsValid)
            {
                Customer = await _context.Commercial
                .Include(c => c.Sites)
                .Include(c => c.Contacts)
                .FirstOrDefaultAsync(m => m.ID == id);

                return Page();
            }
            _context.Address.Add(Site);
            await _context.SaveChangesAsync();
            return RedirectToPage("./Index");  
        }
    }
}

【问题讨论】:

    标签: c# jquery asp.net-core asp.net-core-mvc


    【解决方案1】:

    解决此问题的一种方法是在提交表单之前使用jQuery 执行客户端验证。这样,模式保持打开状态,用户可以立即获得有关错误所在的反馈。

    在这种情况下,另一种替代方法(可能侵入性较小)是将带有模型验证状态的标志从服务器传递回客户端,然后根据此类标志​​的值打开模式,例如

    控制器

       public async Task<IActionResult> OnPostAsync(int? id)
        {
    
            if (!ModelState.IsValid)
            {
                Customer = await _context.Commercial
                .Include(c => c.Sites)
                .Include(c => c.Contacts)
                .FirstOrDefaultAsync(m => m.ID == id);
                ViewData["ModelIsValid"] = false;
                return Page();
            }
            ViewData["ModelIsValid"] = true;
            _context.Address.Add(Site);
            await _context.SaveChangesAsync();
            return RedirectToPage("./Index");  
        }
    

    查看

    <script>
        $(document).ready(function () {
            @if(!(bool)ViewData["ModelIsValid"])
            {
                $("#createSiteModal").modal('show');
            }
        });
    </script>
    

    第二种方法的主要缺点是模式会在页面呈现后弹出,而不是保持打开状态。

    【讨论】:

    • 谢谢@StaticBeagle,我认为第二个选项似乎最好。我不得不插入另一个 ViewData["ModelIsValid"] = true;声明到 OnGetAsync 方法中,否则在发布之前加载页面时我会收到 Null 引用错误。不过,我有一个关于在哪里插入 Javascript 的问题。如果我将它放入由共享视图_Layout.cshtml 呈现的Details.cshtml 视图中,它似乎没有运行。如果我将它放在 _Layout.cshtml 页面中,无论加载什么页面,我都会得到一个空引用异常,因为该变量仅位于 details.cshtml 页面的本地。有什么想法吗?
    • @CarlFoster 你的视图中有一个脚本部分吗?请参阅this answer。 js代码应该去那里。
    • 谢谢@StaticBeagle,效果很好!我想知道 @RenderSection("Scripts", required: false) 是干什么用的!!为了使其正常工作,我必须做的另一件事是插入 $("#createSiteModal").modal('show');在 之间,否则无法识别代码。
    • @CarlFoster haha​​ 我记得当我开始使用 MVC 时,我也曾与 @RenderSection 一起度过那个 aha 时刻。我很高兴能帮上忙。
    • 也可以直接从视图中访问ModelState(如@ViewData.ModelState.IsValid
    猜你喜欢
    • 2019-06-08
    • 2019-03-12
    • 2019-05-06
    • 1970-01-01
    • 1970-01-01
    • 2019-04-17
    • 2018-12-04
    • 2018-03-18
    • 2023-03-21
    相关资源
    最近更新 更多