ITWorker ITWorker - 4 months ago 12
jQuery Question

How to call this post action method using Ajax?

I am trying to create a form that does an Ajax post for a creation of a new user. My goal is to show a popup indicating the result of the action. The current version of the action method adds errors to the ModelState if something's wrong, and redirects if successful.

Action method within AdminController.cs:

[HttpPost]
public async Task<ActionResult> Create(CreateModel model)
{
if (ModelState.IsValid)
{
AppUser user = new AppUser { UserName = model.Name, Email = model.Email };
IdentityResult result = await UserManager.CreateAsync(user,
model.Password);
if (result.Succeeded)
{
return RedirectToAction("Index");
}
else
{
AddErrorsFromResult(result);
}
}
return View(model);
}


The view:

@model IdentityDevelopment.Models.CreateModel
@{ ViewBag.Title = "Create User";}

<h2>Create User</h2>
@Html.ValidationSummary(false)
@using (Html.BeginForm("Create", "Admin", new { returnUrl = Request.Url.AbsoluteUri }))
{
<div class="form-group">
<label>Name</label>
@Html.TextBoxFor(x => x.Name, new { @class = "form-control" })
</div>
<div class="form-group">
<label>Email</label>
@Html.TextBoxFor(x => x.Email, new { @class = "form-control" })
</div>
<div class="form-group">
<label>Password</label>
@Html.PasswordFor(x => x.Password, new { @class = "form-control" })
</div>
<button type="submit" onclick="return showDiv();" class="btn btn-primary">Create</button>
@Html.ActionLink("Cancel", "Index", null, new { @class = "btn btn-default" })


}


<button id="usercreatebutton">Create</button>


As seen above, the button with the "usercreatebutton" id is my development button I want to put the ajax function in:

$("#usercreatebutton")
.button()
.click(function (event) {
alert("ajax post call");
});


The other Create button is for the regular form submit.

The CreateModel:

public class CreateModel
{
[Required]
public string Name { get; set; }
[Required]
public string Email { get; set; }
[Required]
public string Password { get; set; }
}





Based on Shyju's response, I got this working. Below I will post the updates to my code:

In the view, I modified the BeginForm declaration to give the form an id and moved the submit button inside it:

@model IdentityDevelopment.Models.CreateModel
@{ ViewBag.Title = "Create User";}

<h2>Create User</h2>
@Html.ValidationSummary(false)
@using (Html.BeginForm("Create", "Admin", new { returnUrl = Request.Url.AbsoluteUri }, FormMethod.Post, new { @id = "signupform" }))
{
<div class="form-group">
<label>Name</label>
@Html.TextBoxFor(x => x.Name, new { @class = "form-control" })
</div>
<div class="form-group">
<label>Email</label>
@Html.TextBoxFor(x => x.Email, new { @class = "form-control" })
</div>
<div class="form-group">
<label>Password</label>
@Html.PasswordFor(x => x.Password, new { @class = "form-control" })
</div>
<!-- <button type="submit" onclick="return showDiv();" class="btn btn-primary">Create</button> -->

<button type="submit" id="usercreatebutton">Create</button>
@Html.ActionLink("Cancel", "Index", null, new { @class = "btn btn-default" })


}


The controller code was modified to be the one from Shyju's response.

Finally, the javascript code was:

$("form#signupform").submit(function (event) {
event.preventDefault();
var form = $(this);
$.post(form.attr("action"), form.serialize(), function (res) {
if (res.status === "success") {
alert(res.message);
}
else {
alert(res.message);
}
});

});

Answer

First of all, put your submit button inside the form

@using (Html.BeginForm("Create", "Admin", new { returnUrl = Request.Url.AbsoluteUri }))
{   
  // Your existing form elements
  <button type="submit" id="usercreatebutton">Create</button>
}

Now listen to the form submit event get the form ,serialize it and send it. You may use jQuery serialize method to do that.

$.post is a shorthand of $.ajax with POST method type. Let's use that.

$(function(){

  $("form#giveYourFormIdHere" ).submit(function( event ) {

     e.preventDefault();
     var form=$(this);
     $.post(form.attr("action"),form.serialize(),function(res){
        //do something with the res
     });

  });

});

Now, in your HttpPost action, Since we are making an ajax call, we should return a JSON response.

[HttpPost]
public async Task<ActionResult> Create(CreateModel model)
{
    if (ModelState.IsValid)
    {
        AppUser user = new AppUser { UserName = model.Name, Email = model.Email };
        IdentityResult result = await UserManager.CreateAsync(user,
            model.Password);
        if (result.Succeeded)
        {
            return Json(new { status="success"});
        }
        else
        {                
            return Json(new { status="error",message="Some error"});
        }
    }
    return Json(new { status="error", message="Model validation failed"});
}

Update your $.post method's callback to read this JSON data, inspect the property values and do something.

$.post(form.attr("action"),form.serialize(),function(res){
        if(res.status==="success")
        {
          window.location.href="/Admin/Index";
        }
        else
        {
          alert(res.message);
        }
});

If you want to support ajax form submit and normal form submit, You may use Request.IsAjaxRequest() method to conditionally return different responses. Also if you want to return the model validation errors, you may read it from the model state and add the needed info(error messages ?) to the JSON response and display that to user. Here is a post explaining how to read the model errors.