【问题标题】:Why is this AJAX form not working in MVC5?为什么这个 AJAX 表单在 MVC5 中不起作用?
【发布时间】:2014-08-08 01:34:35
【问题描述】:

我正在为带有 .NET 4.5 的 ASP.NET MVC 5 应用程序(Razor 引擎)中使用的网站构建一个联系表单。表单显示正确,并且似乎也可以正确验证,但是 AJAX 部分根本不起作用。

这个想法是,当用户按下提交并且所有验证都成功时,通过 AJAX 联系服务器以发送电子邮件。在此期间,页面应该显示我们在所有 AJAX 事物中看到的“进行中”旋转图标。完成后,服务器返回一个 JSON 响应,指示它是否成功和一条消息。当过程完成时,此信息会显示在 divResult 上。

但正如我所说,当我按下提交时,会显示进度动画,发送电子邮件,而不是在我的 DIV 中获取 JSON 结果,而是将整个页面替换为原始 JSON 响应。我在这里错过了什么?

我的 EmailModel 如下(为了简洁省略验证属性):

public class EmailModel {
    [Required]
    public string Subject { get; set; }
    [Required]
    public string FromEmail { get; set; }
    [Required]
    public string FromName { get; set; }
    [Required]
    public ItemViewModel Receptor { get; set; }
    [Required]
    public string MessageBody { get; set; }
}

“Receptor”只是一个简单的结构,我在联系表单中显示标签列表而不是电子邮件地址,例如“信息”、“反馈”等。它在视图中显示为下拉列表带有给定“标签”的列表,其中一个是预先选择的。

我的 ItemViewModel 如下所示:

public class ItemViewModel {
    public string SelectedId { get; set; }
    public IEnumerable<SelectListItem> Items { get; set; }
}

控制器视图方法非常简单,它只是创建一个 EmailModel 模型实例并设置所有值。然后控制器方法返回一个 ActionResult,如下所示:

EmailModel model = new EmailModel() { ... properties set here ... }
return view(model);

视图将调用以下控制器方法 (Post),该方法也可以正常工作:

[HttpPost]
public JsonResult SendContactMail(Models.EmailModel model) {
    ResponseModel response;
    try {
        if (ModelState.IsValid) {
             response = SendEmail(model);   // pretty obvious what it does and it works
        } else {
            response = new ResponseModel { Success = false, ResponseText = "hum..." };
        }
    } catch (Exception ex) {
         response = new ResponseModel { Success = false, ResponseText = ex.Message };
    }   
}

最后我的 Razor 视图或多或少看起来像这样:

@model Models.EmailModel;
@using System.Web.Mvc.Ajax;
@{
    ViewBag.Title = "contact form";
    System.Web.Mvc.Ajax.AjaxOptions ajaxopts = new AjaxOptions() { 
    HttpMethod = "Post", InsertionMode = InsertionMode.Replace, UpdateTargetId = "divResult",
    OnBegin = "OnBegin", OnComplete = "OnComplete", OnSuccess = "OnSuccess", OnFailure = "OnFailure"
};    

@using (Ajax.BeginForm("SendContactMail", "Mail", null, ajaxopts, 
            new { @encType = "multipart/form-data", @id = "contactusform", 
                  @name = "contactusform" }))
{
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)

    <div class="editor-label">
        @Html.LabelFor(model => model.Subject)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Subject)
        @Html.ValidationMessageFor(model => model.Subject)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.FromEmail)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.FromEmail)
        @Html.ValidationMessageFor(model => model.FromEmail)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.FromName)
    </div>

    <div class="editor-field">
        @Html.EditorFor(model => model.FromName)
        @Html.ValidationMessageFor(model => model.FromName)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.Receptor)
    </div>
    <div class="editor-field">
        @Html.DropDownListFor(model => model.Receptor.SelectedId, Model.Receptor.Items, new { @class = "select1" })
        @Html.ValidationMessageFor(model => model.Receptor)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.MessageBody)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.MessageBody)
        @Html.ValidationMessageFor(model => model.MessageBody)
    </div>

    <p>
        <input type="submit" name="operation" id="process" value="Send" class="btn btn-info" />
    </p>
    </fieldset>

<div id="divProcessing" style="text-align: center;">
    <img src="/Images/ajax-loader.gif" /><br />
    <p>@Resources_Controller_Mail.Msg_SendingEmail</p>
</div>
<div id="divMsg"></div>
<div id="divResult"></div>

}  @* ajax.beginform *@

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")

    <script type="text/javascript">

        $(document).ready(function () {
            // Hide the "busy" Gif at load:
            $("#divProcessing").hide();
            $("#divMsg").hide();

            // Attach click handler to the submit button:
            $('#process').click(function () {
                $('#contactusform').submit();
            });

            // Handle the form submit event, and make the Ajax request:
            $("#contactusform").on("submit", function (event) {
                event.preventDefault();

                // Show the "busy" Gif:
                $("#divProcessing").show();
                $("#divResult").empty();
                var url = $(this).attr("action");
                var formData = $(this).serialize();
                $.ajax({
                    url: url,
                    type: "POST",
                    data: formData,
                    dataType: "json",
                    success: function (resp) {

                        // Hide the "busy" gif:
                        $("#divProcessing").hide();

                        // Do something useful with the data:
                        // var image = resp.Success ? "/Images/Yes.png" : "/Images/No.png";
                        //$("<h3><img src=\"" + image + "\"/></h3>" + "<p>" + resp.ResponseText + "</p>").appendTo("#divResult");
                        $("<h3>" + resp.Success + "</h3>" + "<p>" + resp.ResponseText + "</p>").appendTo("#divResult");
                    }
                })
            });
        });

        function OnBegin() {
            $("#divMsg").append("Ajax Begins");
            $("#divMsg").show();
        }
        function OnComplete() {
            $("#divMsg").append("Ajax Complete");
            $("#divMsg").show();
        }
        function OnSuccess() {
            $("#divMsg").append("Success");
            $("#divMsg").show();
        }
        function OnFailure() {
            $("#divMsg").append("Failed");
            $("#divMsg").show();
        }
    </script>
}

现在在有人问之前...布局在 HTML form 标记关闭之后和上面显示的具有 .ready() 的脚本之前在视图中插入/呈现以下内容 功能:

    <script src="/Scripts/jquery-1.10.2.js"></script>
    <script src="/Scripts/bootstrap.js"></script>
    <script src="/Scripts/respond.js"></script>
    <script src="/Scripts/jquery.validate.js"></script>
    <script src="/Scripts/jquery.validate.unobtrusive.js"></script>

并按照建议将这些插入(感谢您的提示!)在 HEAD 部分。它们来自 MicrosoftMvcAjax.Mvc5 NuGet 包,该包将它们放置在 ~/Scripts 文件夹中:

<script type="text/javascript" src="/Scripts/MicrosoftAjax.js"></script>
<script type="text/javascript" src="/Scripts/MicrosoftMvcAjax.js"></script>

因此总结...

  • 为什么视图上没有 AJAX 进度活动?
  • 为什么视图在提交时表现得像普通的 HTTP 帖子(没有 ajax)?

【问题讨论】:

    标签: jquery ajax asp.net-mvc asp.net-mvc-5


    【解决方案1】:

    你没有包含 ajax

    <script src="/Content/MicrosoftAjax.debug.js" type="text/javascript"></script>
    <script src="/Content/MicrosoftMvcAjax.debug.js" type="text/javascript"></script>
    

    http://www.hanselman.com/blog/ASPNETMVCPreview4UsingAjaxAndAjaxForm.aspx

    【讨论】:

    • 感谢@Tony 的提示,我确实错过了这些。添加了 MicrosoftMvcAjax.Mvc5 NuGet 包,将它们放在我的 ~/Scripts 文件夹中。但是,行为仍然相同。
    【解决方案2】:

    在您的 HTML 中:

     <input type="submit" name="operation" id="process" value="Send" class="btn btn-info" /> ...
    

    使用:

    <button id="process" value="Send" class="btn btn-info" >Submit</button> ...
    

    在 JS 中改变它

        // Handle the form submit event, and make the Ajax request:
                    $("#contactusform").on("submit", function (event) {
                        event.preventDefault();
    // Show the "busy" Gif:
                    $("#divProcessing").show();
                    $("#divResult").empty();
                    var url = $(this).attr("action");
                    var formData = $(this).serialize();
    

    进入

     // Handle the form submit event, and make the Ajax request:
                    $("#process").on("click", function (event) {
                        event.preventDefault();
    // Show the "busy" Gif:
                    $("#divProcessing").show();
                    $("#divResult").empty();
                    var url = $('#contactusform').attr("action");
                    var formData = $('#contactusform').serialize();
    

    【讨论】:

    • 非常感谢@sylwester 改进了很多。现在我看到一个不同的按钮(而不是输入类型提交),当我单击它时,我看到 AJAX 动画指示进度。然而,它似乎永远这样做。以我当前的配置发送电子邮件非常快。越来越近了。
    • 如果您的 ajax 调用的其余部分看起来正常,如果从控制器获得响应,只需检查开发人员工具。
    • 刚刚做了,在它没有显示 AJAX 动画之前,它发送了电子邮件并向我显示了纯文本 JSON 响应(而不是更新页面 DIVresult)。然而,现在它确实显示了 AJAX 动画,但它从不调用 POST 方法,只是再次调用相同的索引(表单)页面。
    • 更改了我的 Ajax.BeginForm 重载并使用 @id/@name 代替 id,因此现在呈现的 HTML 具有指定的表单 ID。结果,现在实际调用了 HTTPPOST 方法并发送了邮件,因为脚本现在可以通过 ID 找到表单。但是,似乎没有调用任何 OnBEgin/OnComplete/etc 方法(放置了一个我从未见过的警报)。现在唯一剩下的问题是 JSON 响应没有放在 divResult 上,而是整个页面都被替换了。
    • 如果你想调用所有这些 OnBEgin/OnComplete 函数,你需要在你的 ajax 调用中包含对它们的引用,即: $.ajax({... .success: OnSuccess(result),error: OnFailure()... })
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-25
    相关资源
    最近更新 更多