0

I want to retrieve the response from my ASP.NET Core Controller through AJAX. Here's the example of my code

public IActionResult Submit(ViewModel model) {
    var isValid = true;
    if (isValid) {
        return Json(new {
            success = true
        });
    }
    return Json(new {
        success = false
    });
}

CSHTML part

<form asp-action="Submit" asp-controller="Home" id="formSubmit" name="formSubmit" method="post" enctype="multipart/form-data">
    <input type="text" id="Name" name="Name">
    <input type="text" id="Address" name="Address">
    <input type="text" id="JobDescription" name="JobDescription">
</form>
$("#formSubmit").on('submit', function(e) {
  var datas = {
    Name: $("input[name='Name']").val(),
    Address: $("input[name='Address']").val(),
    JobDescription: $("input[name='JobDescription']").val()
  };
  var formAction = $(this).attr("action");
  $.ajax({
    method: "POST",
    url: formAction,
    data: JSON.stringify(datas),
    dataType: "json",
    contentType: 'application/json',
    success: function(response) {
      if (response.success) {
        alert("Test");
        return true;
      } else {
        alert("Invalid/Error");
        e.preventDefault();
      }
    });
  });

The problem in this code it redirect/loading to page showing the {"success":false}.

My ViewModel

public class ViewModel{
    public string Name { get; set; }
    public string Address { get; set; }
    public string JobDescription { get; set; }
}
noob101
  • 13
  • 10
  • 2
    Try looking in the browser development tools to see exactly what is being returned. Also ajax is asynchronous, and you are calling e.preventDefault() on the success callback – ste-fu Nov 20 '18 at 09:29
  • success value was not being return in success: function (response) { } – noob101 Nov 20 '18 at 09:33
  • 1
    Put the `e.preventDefault();` call as the first line of the `submit` event handler. You're performing it in the callback at the moment, which is too late., – Rory McCrossan Nov 20 '18 at 09:40
  • Related to the asyncronous call. https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call?rq=1 – Cleptus Nov 20 '18 at 09:40
  • @RoryMcCrossan In case it was valid, the post would already have been canceled. – Cleptus Nov 20 '18 at 09:42
  • @bradbury9 thats not relevant here as the OP is not attempting to return a value. – Rory McCrossan Nov 20 '18 at 09:42
  • @bradbury9 no it won't. With the current logic the form submission will be cancelled after it's already happened, as it waits for the AJAX response. – Rory McCrossan Nov 20 '18 at 09:42
  • @RoryMcCrossan I tried to put e.preventDefault(); as you said but it didnt hit on my debug point in controller. – noob101 Nov 20 '18 at 09:48
  • @bradbury9 I tried to put async: false on my ajax and still redirect/loading to page showing the {"success":false} – noob101 Nov 20 '18 at 09:48
  • @noob101 in that case check the console for errors, and ensure that the URL you're using is correct. It would also be worth adding an `error` handler to aid debugging. Also, never use `async: false`. – Rory McCrossan Nov 20 '18 at 09:49
  • 1
    @RoryMcCrossan thanks, I found out that I'm getting HTTP Error 400 (Bad Request) I already use JSON.stringify, any idea? – noob101 Nov 20 '18 at 09:55
  • That would indicate an issue with your ASP logic which is binding the request to your ViewModel. Without seeing that or the data you're sending, we can't really help – Rory McCrossan Nov 20 '18 at 09:56
  • @RoryMcCrossan wait a moment I'll update the example code which I gave before. I cant really give a whole code for some reason. – noob101 Nov 20 '18 at 09:58
  • What's the value of `formAction`? – Liam Nov 20 '18 at 10:06
  • @RoryMcCrossan done updating the example code above. – noob101 Nov 20 '18 at 10:07
  • Your logic looks fine. Try using just `data: datas,` and remove `contentType` completely. – Rory McCrossan Nov 20 '18 at 10:08
  • 1
    @Liam the formAction value is Home/Submit. see the updated example code above I added var formAction = $(this).attr("action"); – noob101 Nov 20 '18 at 10:09
  • @RoryMcCrossan still getting HTTP Error 400 (Bad Request). – noob101 Nov 20 '18 at 10:18

2 Answers2

0

it seems there are a few issues present here

<form asp-action="Submit" asp-controller="Home" id="formSubmit" name="formSubmit" method="post" enctype="multipart/form-data">

You are specifying asp-action and asp-controller. Omit all of these properties. Start with just:

<form>...</form>

The reason being, when you set those attributes it uses the old-school form submission mechanism which redirects (one of the side affects you listed).

Also the name type seems to be a mismatch, you use ViewModel but in your example the type name is TFAViewModel

Try the following, above your controller (for each method) or above the method itself add

[Consumes("application/json")]
[Produces("application/json")]
public IActionResult Submit([FromBody]ViewModel model)
{
  ModelState.IsValid; //use to inspect. You will also see any violations
  ....

}

In your JS code ensure to do the following (as has been commented)

e.preventDefault(); //stops redirect
Neal
  • 573
  • 3
  • 16
  • sorry for the late response. I tried the solution that you gave and now I'm getting HTTP Error 401 (Unauthorized error). – noob101 Nov 20 '18 at 12:23
  • 1
    OK. Add [AllowAnonymous] as another attribute above Consumes. It's always a good sign when your errors are changing. Means something is progressing and you're closer to your solution. You may have some default [Authorize] attribute somewhere. Just also ensure you aren't requiring an anti-forgery token either – Neal Nov 20 '18 at 12:37
  • Yes, I'm using [Authorize] attribute. I put [AllowAnonymous] as you said but I'm still getting HTTP Error 400 (Bad Request) and I tried to put [ValidateAntiForgeryToken] and still getting HTTP Error 400 (Bad Request). – noob101 Nov 20 '18 at 13:03
  • Cool, allow anonymous prevents 401 (Unauthorized). Now you have 400 Bad request. Which means that your modelstate is invalid. Like I proposed in the answer, add a breakpoint in the first line and inspect ModelState. Most likely ModelState.IsValid = false, and you have a violation. You can inspect violations in ModelState.Values. I have also noticed you sending TitleCaseFromJavascript. This is incorrect, you need to send camelCase (it should auto resolve between C# convention and JS convention) Good luck. – Neal Nov 20 '18 at 13:07
  • If you have issues with the camelCase TitleCase mapping add this to your startup file services.AddMvc(options => { options.RespectBrowserAcceptHeader = true; }).AddJsonOptions(options => { options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }) – Neal Nov 20 '18 at 13:08
  • I have a problem on that the debug on my controller is not hitting at all. I tried to change my url in different ways like url:'@Url.Action("Submit","Home")', url: 'Submit' or url: 'Home/Submit' but none of those works to hit the debug point on my controller. – noob101 Nov 20 '18 at 13:17
0

Have you use [HttpPost] attribute on the Submit action? You need to set a specific url like "/Home/Submit" and have a reference to jquery.

Action:

[HttpPost]
    [Consumes("application/json")]
    [Produces("application/json")]
    public IActionResult Submit(ViewModel model)
    {
        var isValid = true;
        if (isValid)
        {
            return Json(new
            {
                success = true
            });
        }
        return Json(new
        {
            success = false
        });
    }

View:

<form id="formSubmit" name="formSubmit" method="post" enctype="multipart/form-data">
<input type="text" id="Name" name="Name">
<input type="text" id="Address" name="Address">
<input type="text" id="JobDescription" name="JobDescription">
<input type="submit" value="Create" class="btn btn-default" />
</form>

@section Scripts{
<script src="~/lib/jquery/dist/jquery.js"></script>
<script>
    $("#formSubmit").on('submit', function (e) {
        var datas = {
            Name: $("input[name='Name']").val(),
            Address: $("input[name='Address']").val(),
            JobDescription: $("input[name='JobDescription']").val()
        };
        e.preventDefault();
        //var formAction = $(this).attr("action");
        $.ajax({
            method: "POST",
            url: "/Home/Submit",
            data: JSON.stringify(datas),
            dataType: "json",
            contentType: 'application/json',
            success: function (response) {
                if (response.success) {
                    alert("Test");
                    return true;
                } else {
                    alert("Invalid/Error");
                   // e.preventDefault();
                }
            }
        });
    });
</script>
}
Ryan
  • 19,118
  • 10
  • 37
  • 53