46

I have a simple form created using Ajax.BeginForm:

<% using (Ajax.BeginForm("Update", "Description", new { id = Model.Id },
     new AjaxOptions
     {
       UpdateTargetId = "DescriptionDiv",
       HttpMethod = "post"
     },new {id ='AjaxForm' })) {%>
Description:
<%= Html.TextBox("Description", Model.Description) %><br />
<input type="submit" value="save" />
<% }%>

The controller is wired up and returns a partial view that updates the DescriptionDiv. And it all works neatly.

Now I would like to be able to submit this form without having the submit button (via a clik on a link or on an image or whatever). Unfortunately this little jQuery snippet does not do the job:

$('form#AjaxForm').submit();

It does submit the form, but does (I suppose not surprisingly) a regular post-back and not an Ajax one.

For the sake of simplicity the above jQuery is wired up like this:

<a href="#" onclick="$('form#AjaxForm').submit(); return false;">submit</a>

The form's onsubmit is using the Sys.Mvc.AsyncForm.handleSubmit() but the jQuery submit seems to be bypassing this.

PS. I am looking for a solution in this particular approach. I know how to achieve the same using a normal form and posting it using AJAX+jQuery. I am interested in this particular solution though.

mfloryan
  • 7,667
  • 4
  • 31
  • 44

8 Answers8

41

I'm going to assume that your lack of quotes around the selector is just a transcription error, but you should check it anyway. Also, I don't see where you are actually giving the form an id. Usually you do this with the htmlAttributes parameter. I don't see you using the signature that has it. Again, though, if the form is submitting at all, this could be a transcription error.

If the selector and the id aren't the problem I'm suspicious that it might be because the click handler is added via markup when you use the Ajax BeginForm extension. You might try using $('form').trigger('submit') or in the worst case, have the click handler on the anchor create a hidden submit button in the form and click it. Or even create your own ajax submission using pure jQuery (which is probably what I would do).

Lastly, you should realize that by replacing the submit button, you're going to totally break this for people who don't have javascript enabled. The way around this is to also have a button hidden using a noscript tag and handle both AJAX and non-AJAX posts on the server.

BTW, it's consider standard practice, Microsoft not withstanding, to add the handlers via javascript not via markup. This keeps your javascript organized in one place so you can more easily see what's going on on the form. Here's an example of how I would use the trigger mechanism.

  $(function() {
      $('form#ajaxForm').find('a.submit-link').click( function() {
           $('form#ajaxForm').trigger('submit');
      }).show();
  }

<% using (Ajax.BeginForm("Update", "Description", new { id = Model.Id },
     new AjaxOptions
     {
       UpdateTargetId = "DescriptionDiv",
       HttpMethod = "post"
     }, new { id = "ajaxForm" } )) {%>
   Description:
   <%= Html.TextBox("Description", Model.Description) %><br />
   <a href="#" class="submit-link" style="display: none;">Save</a>
   <noscript>
       <input type="submit" value="Save" />
   </noscript>
<% } %>
tvanfosson
  • 524,688
  • 99
  • 697
  • 795
  • Thanks for your comments. It all makes sense - I was putting the example quickly together hence no quotes and explicit Id for the form (they exist in the real application). Indeed doing it all with jQuery is clearer but not an option at this moment. – mfloryan Aug 20 '09 at 13:35
  • Actually, this doesn't work in all browsers. It works in Safari and Firefox but not IE and Chrome. In Safri/Firefox triggering the 'submit' event works in Chrome/IE, triggering 'onsubmit' works and triggering 'submit' actually causes a traditional non-ajax post to happen. – Brian Reiter Jan 03 '11 at 20:52
  • 14
    `$('form#ajaxForm').submit();` Worked for me with jQuery 1.4.4 and MVC 3. BUT I took me a long time to figure out that you need to have some script files referenced or this will fall back to regular post-back. The files are in my case: jquery.unobtrusive-ajax.(min.)js + MicrosoftAjax and MicrosoftMvcAjax – juhan_h May 25 '11 at 06:24
  • 1
    If the difference is .submit() to .trigger('submit');, it doesn't fix the problem. – Levitikon Sep 16 '11 at 15:46
  • 4
    loading jquery.unobtrusive-ajax.(min.)js helped me as well. – twk Feb 29 '12 at 14:36
  • If I need to bypass the form validation in this case, how to achieve that? – Vad Nov 13 '15 at 16:33
  • @Vad don't load the validation JS on the page – tvanfosson Nov 13 '15 at 18:31
  • @tvanfosson I have a link "Remove Address" that calls JS to do some job and then make a postback. This link does not need validation. And I have "Save" submit button that needs validation. I do not want to disable client-side validation completely. – Vad Nov 13 '15 at 18:41
  • @Vad in that case I would have the JS not trigger the button, but do the postback itself without invoking the validation logic – tvanfosson Nov 13 '15 at 18:59
7

A simple example, where a change on a dropdown list triggers an ajax form-submit to reload a datagrid:

<div id="pnlSearch">

    <% using (Ajax.BeginForm("UserSearch", "Home", new AjaxOptions { UpdateTargetId = "pnlSearchResults" }, new { id="UserSearchForm" }))
    { %>

        UserType: <%: Html.DropDownList("FilterUserType", Model.UserTypes, "--", new { onchange = "$('#UserSearchForm').trigger('submit');" })%>

    <% } %>

</div>

The trigger('onsubmit') is the key thing: it calls the onsubmit function that MVC has grafted onto the form.

NB. The UserSearchResults controller returns a PartialView that renders a table using the supplied Model

<div id="pnlSearchResults">
    <% Html.RenderPartial("UserSearchResults", Model); %>
</div>
Abel
  • 56,041
  • 24
  • 146
  • 247
James McCormack
  • 9,217
  • 3
  • 47
  • 57
  • @Abel are you sure about your edit? I recall at the time it was very specifically trigger('onsubmit'), NOT trigger('submit'). – James McCormack May 04 '12 at 16:46
  • Well, I tried your solution and using `onsubmit` raised a JS error, using `submit` didn't. Simple as that. I didn't really give it much more thought though. – Abel May 04 '12 at 16:56
6

Unfortunately triggering the onsubmit or submit events wont work in all browsers.

  • Works in IE and Chrome: #('form#ajaxForm')trigger('onsubmit');
  • Works in Firefox and Safari: #('form#ajaxForm')trigger('submit');

Also, if you trigger('submit') in Chrome or IE, it causes the entire page to be posted rather than doing an AJAX behavior.

What works for all browsers is removing the onsubmit event behavior and just calling submit() on the form itself.

<script type="text/javascript">
$(function() {

    $('form#ajaxForm').submit(function(event) { 
        eval($(this).attr('onsubmit')); return false; 
        });

    $('form#ajaxForm').find('a.submit-link').click( function() { 
        $'form#ajaxForm').submit();
        });

  }
</script>
  <% using (Ajax.BeginForm("Update", "Description", new { id = Model.Id },
     new AjaxOptions
     {
       UpdateTargetId = "DescriptionDiv",
       HttpMethod = "post"
     }, new { id = "ajaxForm" } )) {%>
   Description:
   <%= Html.TextBox("Description", Model.Description) %><br />
   <a href="#" class="submit-link">Save</a> 
<% } %>

Also, the link doesn't have to be contained within the form in order for this to work.

Brian Reiter
  • 1,339
  • 1
  • 10
  • 16
3

I've tried a few times to get the ajax form submit working nicely, but always met with either complete failure or too many compromises. Here's an example of page that uses the jQuery Form plug-in inside of a MVC page to update a list of projects (using a partially rendered control) as the user types in an input box:

<div class="searchBar">
    <form action="<%= Url.Action ("SearchByName") %>" method="get" class="searchSubmitForm">
        <label for="projectName">Search:</label>
        <%= Html.TextBox ("projectName") %>
        <input class="submit" type="submit" value="Search" />
    </form>
</div>
<div id="projectList">
    <% Html.RenderPartial ("ProjectList", Model); %>
</div>

<script type="text/javascript">
    jQuery(document).ready(function() {
        jQuery("#projectName").keyup(function() {
            jQuery(".searchSubmitForm").submit();
        });

        jQuery(".searchSubmitForm").submit(function() {
            var options = {
                target : '#projectList'
            }

            jQuery(this).ajaxSubmit(options);

            return false;
        });

        // We remove the submit button here - good Javascript depreciation technique
        jQuery(".submit").remove();
    });
</script>

And on the controller side:

public ActionResult SearchByName (string projectName)
{
    var service = Factory.GetService<IProjectService> ();
    var result = service.GetProjects (projectName);

    if (Request.IsAjaxRequest ())
        return PartialView ("ProjectList", result);
    else
    {
        TempData["Result"] = result;
        TempData["SearchCriteria"] = projectName;

        return RedirectToAction ("Index");
    }
}

public ActionResult Index ()
{
    IQueryable<Project> projects;
    if (TempData["Result"] != null)
        projects = (IQueryable<Project>)TempData["Result"];
    else
    {
        var service = Factory.GetService<IProjectService> ();
        projects = service.GetProjects ();
    }

    ViewData["projectName"] = TempData["SearchCriteria"];

    return View (projects);
}
Kieron
  • 26,748
  • 16
  • 78
  • 122
  • Thank you for this example, but I am trying to get to the bottom of this specific issue - as I noted I have an alternative solution working with jQuery but I cannot use it. – mfloryan Aug 20 '09 at 13:29
2

Ajax.BeginForm looks to be a fail.

Using a regular Html.Begin for, this does the trick just nicely:

$('#detailsform').submit(function(e) {
    e.preventDefault();
    $.post($(this).attr("action"), $(this).serialize(), function(r) {
        $("#edit").html(r);
    });
}); 
Levitikon
  • 7,749
  • 9
  • 56
  • 74
2

Try the following way:

<input type="submit" value="Search" class="search-btn" />
<a href="javascript:;" onclick="$('.search-btn').click();">Go</a>
Ashley Medway
  • 7,151
  • 7
  • 49
  • 71
0

Rather than using JavaScript perhaps try something like

<a href="#">

  <input type="submit" value="save" style="background: transparent none; border: 0px none; text-decoration: inherit; color: inherit; cursor: inherit" />

</a>
Benjamin
  • 131
  • 1
  • 6
0

Simply place normal button indide Ajax.BeginForm and on click find parent form and normal submit. Ajax form in Razor:

@using (Ajax.BeginForm("AjaxPost", "Home", ajaxOptions))
    {        
        <div class="form-group">
            <div class="col-md-12">

                <button class="btn btn-primary" role="button" type="button" onclick="submitParentForm($(this))">Submit parent from Jquery</button>
            </div>
        </div>
    }

and Javascript:

function submitParentForm(sender) {
    var $formToSubmit = $(sender).closest('form');

    $formToSubmit.submit();
}
Jason Evans
  • 28,906
  • 14
  • 90
  • 154