Why is this AJAX form not working in MVC5?

13,769

Solution 1

You didnt include 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

Solution 2

In your HTML Instead:

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

use:

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

and in JS change that

    // 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();

into

 // 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();
Share:
13,769
Lord of Scripts
Author by

Lord of Scripts

Technical Technically speaking I have experience with too many things so I will name only those that interest me most: UML, .NET, Electronics, Embedded systems. I am a former Linux fanatic seduced to Windows by the dark forces of the Microsoft overlord. Linux has tried so hard to become Windows-like that I lost all interest in locking myself in it as my primary platform. I developed MANY freeware open-source utilities. I was one of the original developers of the most successful Microsoft Messenger clone on the Linux platform where I implemented many of the core features and a few features not available in the Microsoft version. I developed the 1st Linux package update utility before RedHat and other clones copied the concept and made it an integral part of their platforms. Published several technical articles and was a co-author of the Apache Server Unleashed book. Hobbies I love flight simulation to the point that I have a simple home cockpit, I learned to read aeronautical charts and to navigate using them. In addition to traveling (and travel writing) I also enjoy writing fiction. Justice and Political I am not politically biased but for years I have been fighting an act of corruption in Panama where a member of the Asamblea Nacional conspired with other of his party-members (helped by the now ex-president) to steal a land plot that has been part of the family since the 1880's without paying for the damages or the property itself. This crime has gone unpunished.

Updated on June 04, 2022

Comments

  • Lord of Scripts
    Lord of Scripts almost 2 years

    I am building a contact form for the website which is used in an ASP.NET MVC 5 application (Razor engine) with .NET 4.5. The form displays correctly and also seems to validate properly, however the AJAX part does not work at all.

    The idea is that when the user presses SUBMIT and all validations are successful that the server is contacted via AJAX to send the email. During this time the page should display the "in progress" rotating icon we see with all AJAX things. When done the server returns a JSON response indicating whether it was successful or not and a message. This information is then displayed on the divResult when the process finishes.

    But as I said, when I press submit the progress animation is shown, the email is sent and rather than getting the JSON result in my DIV, the whole page is replaced by the raw JSON response. What am I missing here?

    My EmailModel is as follows (omitting validation attributes for brevity):

    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; }
    }
    

    The "Receptor" is simply a construct whereby I show a list of tags in the contact form rather than the email address, for example "Info", "Feedback", etc. It is displayed in the view as a drop down list with the given "tags" and one of those is pre-selected.

    My ItemViewModel looks like this:

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

    The controller view method is pretty simple, it just creates an EmailModel model instance and sets all the values. Then the controller method returns an ActionResult like this:

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

    The view would invoke the following controller method (Post) which also works fine:

    [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 };
        }   
    }
    

    Finally my Razor view looks like this more or less:

    @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>
    }
    

    Now before somebody asks... the layout inserts/renders the following in the view AFTER the HTML form tag closes and just BEFORE the script shown above that has the .ready() function:

        <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>
    

    And these are inserted (thanks for that tip!) in the HEAD section as suggested. They come from the MicrosoftMvcAjax.Mvc5 NuGet package which places them in the ~/Scripts folder:

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

    Thus summarizing...

    • Why is there no AJAX progress activity on the view?
    • Why the view behaves like a regular HTTP post (without ajax) on submit?