views:

4268

answers:

4

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.

+4  A: 

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
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
+1  A: 

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

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('onsubmit');" })%>

    <% } %>

</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>
James McCormack
A: 

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