下拉列表的远程功能和验证不适用于弹出模式

Remote function and validation for dropdownlistfor not working in pop-up modal

当我没有为 create/edit 操作使用弹出模式时一切正常,并且在我更新我的代码并且已经使用弹出模式之后,远程功能没有触发并且 dropdownlistfor 的验证是无法正常工作。

模态显示代码:

<a class="btn btn-sm btn-success btn-flat" onclick="showModal('@Url.Action("CreateOrEditProduct", "Purchases", new { pid=Model.Id, pn=Model.PurchaseNumber },
                                                                                                          Context.Request.Scheme)', 'Add Product', '#productForm')"><i class="fas fa-plus"></i> Add Product</a>

控制器中的代码:

public async Task<IActionResult> CreateOrEditProduct(int id = 0, int pid = 0, string pn = "")
    {
        PurchaseDetailViewModel vmodel = new PurchaseDetailViewModel();
        if (id == 0)
        {
            /*create view code here*/
        }
        else
        {
            /*edit view code here*/
        }

        vmodel.Products = ProductList();
        vmodel.Suppliers = SupplierList();

        return View(vmodel);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> CreateOrEditProduct(int id, PurchaseDetailViewModel purchaseDetail)
    {
        purchaseDetail.Products = ProductList();
        purchaseDetail.Suppliers = SupplierList();
        if (ModelState.IsValid)
        {
            var vmodel = _mapper.Map<PurchaseDetail>(purchaseDetail);
            if (id == 0)
            {
                /*create code here*/
            }
            else
            {
                /*edit code here*/
            }

            return Json(new { isValid = true, html = this.RenderViewAsync("Details", purchaseDetail) });
        }
        return Json(new
        {
            isValid = false,
            html = this.RenderViewAsync("CreateOrEditProduct", purchaseDetail)
        });
    }

表单代码:

    <form id="productForm" asp-action="CreateOrEditProduct" onsubmit="return jQueryAjaxPost(this);" autocomplete="off">
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>

    @Html.HiddenFor(Model => Model.PurchaseId)
    @Html.HiddenFor(Model => Model.PurchaseNumber)

    <div class="form-group">
        <label asp-for="ProductId" class="control-label"></label>
        @Html.DropDownListFor(x => Model.ProductId, Model.Products, "**Please select**",
        htmlAttributes: new { @class = "form-control", @id = "Product" })
        @Html.ValidationMessageFor(Model => Model.ProductId, "", new { @class = "text-danger" })
    </div>

    /*some other inputs here*/

    <div class="form-group">
        <button type="submit" class="btn btn-success btn-flat"><i class="far fa-check-circle"></i> Save</button>
        <a class="btn btn-danger btn-flat" asp-controller="Purchases" asp-action="Details" asp-route-id="@Model.PurchaseId"><i class="far fa-times-circle"></i> Cancel</a>
    </div>
</form>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}

Ajax 在此处显示表格和 post 代码:

    showModal = (url, title, formid) => {
    $.ajax({
        type: 'GET',
        url: url,
        success: function (res) {
            //$.validator.unobtrusive.parse(formid);
            $('#form-modal .modal-body').html(res);
            $('#form-modal .modal-title').html(title);
            $('#form-modal').modal('show');
        }
    })
}

jQueryAjaxPost = form => {
    try {
        $.ajax({
            type: 'POST',
            url: form.action,
            data: new FormData(form),
            contentType: false,
            processData: false,
            success: function (res) {
                console.log(res);
                if (res.isValid) {
                    //$('#view-all').html(res.html)
                    $('#form-modal .modal-body').html('');
                    $('#form-modal .modal-title').html('');
                    $('#form-modal').modal('hide');
                }
                else
                    $('#form-modal .modal-body').html(res.html.result);
            },
            error: function (err) {
                console.log(err)
            }
        })
        //to prevent default form submit event
        return false;
    } catch (ex) {
        console.log(ex)
    }
}

代码下拉列表:

private IList<SelectListItem> ProductList()
    {
        var list = _context.Product.Select(x => new SelectListItem { Text = x.ProductName, Value = x.Id.ToString() }).ToList();
        return list;
    }

控制器扩展:

public static class ControllerExtensions
{
    public static async Task<string> RenderViewAsync<TModel>(this Controller controller, string viewName, TModel model, bool partial = false)
    {
        if (string.IsNullOrEmpty(viewName))
        {
            viewName = controller.ControllerContext.ActionDescriptor.ActionName;
        }

        controller.ViewData.Model = model;

        using (var writer = new StringWriter())
        {
            IViewEngine viewEngine = controller.HttpContext.RequestServices.GetService(typeof(ICompositeViewEngine)) as ICompositeViewEngine;
            ViewEngineResult viewResult = viewEngine.FindView(controller.ControllerContext, viewName, !partial);

            if (viewResult.Success == false)
            {
                return $"A view with the name {viewName} could not be found";
            }

            ViewContext viewContext = new ViewContext(
                controller.ControllerContext,
                viewResult.View,
                controller.ViewData,
                controller.TempData,
                writer,
                new HtmlHelperOptions()
            );

            await viewResult.View.RenderAsync(viewContext);

            return writer.GetStringBuilder().ToString();
        }
    }
}

查看模型代码,并且已经检查远程功能在没有模态的情况下工作

 public class PurchaseDetailViewModel
    {
        public int Id { get; set; }

        [Display(Name ="Product"), Required]
        [Remote("CheckPurchaseProduct", "Purchases", AdditionalFields = "PurchaseId", ErrorMessage = "Product already exists.")]
        public int ProductId { get; set; }

        public IList<SelectListItem> Products { get; set; }

/*other fields here*/
}

没有模态的示例输出:

Output without modal

模态输出示例:

Output with modal

我已经搜索了几个小时,但无法解决问题

你的 razor 视图中的模式似乎没有使用 Layout.If 所以你不能在那个 razor 视图中使用 @section Script{}

这是我的简单演示,您可以查看:

1.Index.cshtml:

@model PurchaseDetailViewModel
<a class="btn btn-sm btn-success btn-flat" onclick="showModal('@Url.Action("CreateOrEditProduct", "Home", new { pid=Model.Id, pn=Model.PurchaseNumber })')">open</a>
<div class="modal fade" id="form-modal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close" onclick="Close()">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            <div class="modal-body" id="details">

            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-dismiss="modal" onclick="Close()">Close</button>
                <button type="button" class="btn btn-primary">Save changes</button>
            </div>
        </div>
    </div>
</div>
@section Scripts {
<script>
    showModal = (url, title, formid) => {
        $.ajax({
            type: 'GET',
            url: url,
            success: function (res) {
                $('#form-modal .modal-body').html(res);
                $('#form-modal').modal('show');
            }
        })
    }

    jQueryAjaxPost = form => {
        try {
               //...
            })
            //to prevent default form submit event
            return false;
        } catch (ex) {
            console.log(ex)
        }
    }
</script>
}

2.CreateOrEditProduct.cshtml:

@model PurchaseDetailViewModel
@{
       Layout = null;
}
<form id="productForm" asp-action="CreateOrEditProduct" onsubmit="return jQueryAjaxPost(this);" autocomplete="off">
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>

    @Html.HiddenFor(Model => Model.PurchaseId)
    @Html.HiddenFor(Model => Model.PurchaseNumber)

    <div class="form-group">
        <label asp-for="ProductId" class="control-label"></label>
        @Html.DropDownListFor(x => Model.ProductId, Model.Products, "**Please select**",
     htmlAttributes: new { @class = "form-control", @id = "Product" })
        @Html.ValidationMessageFor(Model => Model.ProductId, "", new { @class = "text-danger" })
    </div>
    <div class="form-group">
        <button type="submit" class="btn btn-success btn-flat"><i class="far fa-check-circle"></i> Save</button>
        <a class="btn btn-danger btn-flat" asp-controller="Purchases" asp-action="Details" asp-route-id="@Model.PurchaseId"><i class="far fa-times-circle"></i> Cancel</a>
    </div>
</form>

@{
     await Html.RenderPartialAsync("_ValidationScriptsPartial");
}

3.Controller:

public class HomeController : Controller
{
    private IList<SelectListItem> ProductList()
    {
        var data = new List<dynamic> {
            new { ProductName ="aaa", Id =1},
            new { ProductName ="bbb", Id =2},
            new { ProductName ="ccc", Id =3}
        };
        var list = data.Select(x => new SelectListItem { Text = x.ProductName, Value = x.Id.ToString() }).ToList();
        return list;
    }
    public IActionResult Index()
    {
        var model = new PurchaseDetailViewModel()
        {
            Id = 1,
            PurchaseNumber = 1001
        };
        return View(model);
    }

    public async Task<IActionResult> CreateOrEditProduct(int id = 0, int pid = 0, string pn = "")
    {
        PurchaseDetailViewModel vmodel = new PurchaseDetailViewModel();
        if (id == 0)
        {
            /*create view code here*/
        }
        else
        {
            /*edit view code here*/
        }

        vmodel.Products = ProductList();

        return View(vmodel);
    }

    [AcceptVerbs("GET", "POST")]
    public IActionResult CheckPurchaseProduct()
    {
        return Json(false);
    }
}

4.Result: