MVC 5 Ajax.BeginForm Submit button calls current page instead of URL of Controller and Action specified

2.2k Views Asked by At

I'm trying to use Ajax.BeginForm, so I can pass the value of the checkbox to my Controller Action.

I was using @Ajax.ActionLink, but I can't get the value of the newly introduced checkbox, so I want to use Ajax.BeginForm going forward.

Since @Ajax.ActionLink is working in the View, I assume that Ajax is working properly, so I can rule that out.

Here are a couple of options I have tried. When I hover over the buttons, they both display the URL of my web page instead of the URL of the Controller and Action. When I click on the buttons, the page basically refreshes instead of calling the GetCode Action in the PublicOffers Controller.

Any help is much appreciated! Thanks!

Option 1

<div>
    @using (Ajax.BeginForm("GetCode", "PublicOffers", null, new AjaxOptions()
    {
     UpdateTargetId = "detailsDiv",
     InsertionMode = InsertionMode.Replace,
     HttpMethod = "GET",
     OnBegin = "onStart",
     OnComplete = "onComplete",
     OnSuccess = "myCallback"
    }))
    {
     //bool checkedOption = false;
     //@Html.CheckBoxFor(x => checkedOption, new { Name = "OptIn" })

     @Html.CheckBoxFor(model => model.OptIn);
     @Html.HiddenFor(model => model.Id);

     <input type="submit" value="Get Code" class="button btn-primary" />
     }
</div>

Option 2

<div>    
   @using (Ajax.BeginForm(new AjaxOptions() 
   { HttpMethod = "GET", 
     Url = "PublicOffers/GetCode", 
     InsertionMode = InsertionMode.Replace, 
     UpdateTargetId = "detailsDiv", 
     OnBegin = "onStart", 
     OnComplete = "onComplete", 
     OnSuccess = "myCallback" 
   }))
   {
       //bool checkedOption = false;
       //@Html.CheckBoxFor(x => checkedOption, new { Name = "OptIn" })
       @Html.CheckBoxFor(model => model.OptIn)
       //@Html.HiddenFor(model => model.Id, new { Name = "OfferId" })
       @Html.HiddenFor(model => model.Id);
       @Html.AntiForgeryToken()

       <input type="submit" value="Submit" />
    }
</div>
2

There are 2 best solutions below

2
vscoder On

This is not exactly an answer but it might help.

First be sure you have this, I use NuGet to install it, Microsoft.jQuery.Unobtrusive.Ajax

Then be sure it gets emitted to the page, either though bundle scripts or a script link in the cshtml

First a simple model...

namespace AjaxTest.Models
{
    public class AjaxTestModel
    {
        public bool OptIn { get; set; }

    }
}

Next some cshtml...

@model AjaxTest.Models.AjaxTestModel
@{ ViewBag.Title = "AjaxTest1";}
<h2>AjaxTest1</h2>
@using (Ajax.BeginForm("AjaxTest1", "Home", null,
    new AjaxOptions
    {
        HttpMethod = "POST",
        OnSuccess = "OnSuccess(xhr)",
        OnFailure = "OnFailure(xhr, status)"
    },
    new { id = "myform" }))
{
    @Html.CheckBoxFor(model => model.OptIn);
    <span id="lbl_message"></span>
    <br />
    <button id="btn_submit" type="submit" class="">Submit</button>
}
@section scripts{
    <script>
        $(document).ready(function () {
            console.log("ready to rock and roll....");
        });
        function OnBegin() {
            console.log("OnBegin");
        }
        function OnSuccess(xhr) {
            console.log("OnComplete");
            $("#lbl_message").text("Ok:" + xhr.responseJSON.param2);
        }
        function OnFailure(xhr, status) {
            console.log("OnFailure");
            $("#lbl_message").text("Error:" + xhr.responseJSON.param2);
        }
    </script>
}

The magic is in the controller, notice that I am returning a Json object, not a view.

public class HomeController : Controller
{
    public ActionResult AjaxTest1()
    {
        AjaxTestModel model = new AjaxTestModel();
        return View();
    }
    [HttpPost]
    public ActionResult AjaxTest1(AjaxTestModel model)
    {
        if (model.OptIn)
        {
            dynamic errorMessage = new { param1 = "param1", param2 = "You opted in." };
            HttpContext.Response.StatusCode = (int)HttpStatusCode.OK;
            return Json(errorMessage, JsonRequestBehavior.AllowGet);
        }
        else
        {
            dynamic errorMessage = new { param1 = "param1", param2 = "You opted out." };
            HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
            return Json(errorMessage, JsonRequestBehavior.AllowGet);
        }
    }
}

Note, The HttpContext.Response.StatusCode will control which Ajax callback is activate, return HttpStatusCode.Ok and the OnSuccess gets called, return the HttpStatusCode.NotFound, or most any other error code, and the OnFailure will get called.

0
Dumber_Texan2 On

I got it to work by adding a beginning Ajax.BeginForm method. It's almost like the first instance invokes the second Ajax.BeginForm method. Since there is no button or anything else in the first method, nothing displays on the page.

NOTE: I changed my Get to a Post so the [ValidateAntiForgeryToken] attribute would work on the Controller Action. I read that it would not work with a Get.

<div>
  @using (Ajax.BeginForm("GetCode", "PublicOffers", new { offerId = Model.Id }, new AjaxOptions()
  {
    //Nothing here, but for some reason without this code the Ajax.BeginForm below won't work                                        
  }))
  {
    //Nothing here, but for some reason without this code the Ajax.BeginForm below won't work    
  }
</div>

<div>
  @using (Ajax.BeginForm("GetCode", "PublicOffers", new { offerId = Model.Id },
    new AjaxOptions { OnBegin = "onStart", UpdateTargetId = "detailsDiv",
    InsertionMode = InsertionMode.Replace, HttpMethod = "Post",
    OnComplete = "onComplete",
    OnSuccess = "myCallback"},
    new { @style = "display:inline-block" }))
    {
      @Html.AntiForgeryToken()

      <div class="form-horizontal">
        <div class="form-group">
          @Html.CheckBoxFor(model => model.OptIn, new { Name = "optIn"})
        </div>
      </div>
       <input type="submit" class="button btn-primary" value="Get Code" id="get-code button" />
    }
</div>

Here is my Controller Action.

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> GetCode(Guid offerId, bool optIn = false)
{
  //Code here 

  return PartialView("_OfferCode");
}