FormCollection parameter is empty while using #Ajax.BeginForm and #Ajax.ActionLink - ajax

I've went through whole bunch of SO questions regarding my problem and I wasn't able to find a solution, so I've decided to post this question. The problem is that FormColection fc is empty when I do that Ajax POST request by clicking the search button from _Sidebar.cshtml. What am I missing here?
Code part:
_MyLayout.cshtml:
#using (Ajax.BeginForm("Results", "Search", null, new AjaxOptions { HttpMethod = "POST", InsertionMode = InsertionMode.Replace, UpdateTargetId = "d_content", LoadingElementId = "spinner", OnBegin = "ToggleContent", OnComplete = "ToggleContent" },null))
{
<div class="wrapper row-offcanvas row-offcanvas-left">
<div id="a_sidebar">
#{ Html.RenderAction("_Sidebar"); }
</div>
<aside class="right-side">
<section class="content">
<img id="spinner" src="~/Content/img/lightbox-ico-loading.gif" style="display: none;">
<div id="d_content">
#RenderBody()
</div>
</section>
</aside>
</div>
}
_Sidebar.cshtml:
<ul class="treeview-menu">
<li>
<div class="form-group">
<label>F1</label>
#Html.ListBox("ddF1", (MultiSelectList)ViewData["ddF1"])
</div>
<div class="form-group">
<label>F2</label>
#Html.ListBox("ddF2", (MultiSelectList)ViewData["ddF2"])
</div>
<div class="form-group">
<label>Status</label>
#Html.ListBox("ddStatusFilter", (MultiSelectList)ViewData["ddStatusFilter"])
</div>
<div class="form-group">
<label>Name</label>
#Html.TextBox("tbName")
</div>
</li>
</ul>
<li class="treeview">
<div style="text-align: center;">
<button type="reset" class="btn btn-warning">Clear Filters</button>
#Ajax.ActionLink("Search", "Results", "Search", new { }, new AjaxOptions { HttpMethod = "POST", InsertionMode = InsertionMode.Replace, UpdateTargetId = "d_content", LoadingElementId = "spinner", OnBegin = "ToggleContent", OnComplete = "ToggleContent" }, new { #class = "btn btn-success", #style = "color: white;" })
</div>
</li>
SearchController.cs:
[HttpPost]
[AcceptVerbs(HttpVerbs.Post)]
public PartialViewResult Results(FormCollection fc)
{
//TODO: Implement filtering through FormCollection in passed parameter
// but that freakin' fc var is empty
var model = db.vw_MainTable.ToList();
return PartialView("_SearchResultGrid", model);
}
Much appreciated.

From the code, It looks like you don't need a form tag covering your entire html. You can place it in the _Sidebar.cshtml like this.
Also replace the action link with a submit button (check below code).
#using (Ajax.BeginForm("Results", "Search", null, new AjaxOptions { HttpMethod = "POST", InsertionMode = InsertionMode.Replace, UpdateTargetId = "d_content", LoadingElementId = "spinner", OnBegin = "ToggleContent", OnComplete = "ToggleContent" },null))
{
<ul class="treeview-menu">
<li>
<div class="form-group">
<label>F1</label>
#Html.ListBox("ddF1", (MultiSelectList)ViewData["ddF1"])
</div>
<div class="form-group">
<label>F2</label>
#Html.ListBox("ddF2", (MultiSelectList)ViewData["ddF2"])
</div>
<div class="form-group">
<label>Status</label>
#Html.ListBox("ddStatusFilter", (MultiSelectList)ViewData["ddStatusFilter"])
</div>
<div class="form-group">
<label>Name</label>
#Html.TextBox("tbName")
</div>
</li>
</ul>
<li class="treeview">
<div style="text-align: center;">
<button type="reset" class="btn btn-warning">Clear Filters</button>
<button type="submit" class="btn"> Search</button>
</div>
</li
}

There might be multiple reasons for this. In my case, it was happening because my form fields only had the ID property and not the Name property.
After adding the Name property to the input fields, the Controller could see them just fine.

Related

MVC 5 Ajax posting whole form - instead of ajax call

I have a basic ajax call setup in MVC 5 but it seems that my Ajax form is actually posting the full form, instead of getting back PartialViewResult in the main view, the whole window just renders with the PartialView for the result
suggestion what I may be missing here ?
I also do have the following jquery renders in my _Layout.cshtml
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryval")
MainView
#{
ViewBag.Title = "Puzzles 1 & 2";
}
<h2>#ViewBag.Title</h2>
<div>
#Html.Partial("Puzzle1Form")
</div>
PartialView
#model SixPivot_Code_Puzzles.Models.Puzzle1Model
#using (Ajax.BeginForm("Puzzle1","Puzzles",new AjaxOptions {
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
UpdateTargetId = "puzzle1-result",
}))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Puzzle1</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.IntegerList, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.IntegerList, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.IntegerList, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Find Largest No." class="btn btn-default" />
</div>
</div>
</div>
}
<div id="puzzle1-result"></div>
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
}
Controller
[HttpPost]
public PartialViewResult Puzzle1(Puzzle1Model model)
{
if (ModelState.IsValid)
{
Puzzle1Model result = new Puzzle1Model();
result.LargestInteger = FindLargestInt(model.IntegerList).ToString();
result.IntegerList = model.IntegerList;
return PartialView("Puzzle1FormResult",result);
}
else {
return PartialView("Puzzle1Form",model);
}
}
PartialViewResult on Success (Puzzle1FormResult.cshtml)
#model SixPivot_Code_Puzzles.Models.Puzzle1Model
<div>
<h4>Largest Integer</h4>
<hr />
<p>
Largest Integer for the list "#Model.IntegerList" is : #Model.LargestInteger
</p>
</div>
I tend to try not use the Ajax helpers in MVC because I find jQuery easier to understand. You could try doing it how I would.
PartialView
#model SixPivot_Code_Puzzles.Models.Puzzle1Model
<form class="form-horizontal" id="frmPuzzle1">
#Html.AntiForgeryToken()
<div>
<h4>Puzzle1</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.IntegerList, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.IntegerList, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.IntegerList, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Find Largest No." class="btn btn-default" />
</div>
</div>
</div>
<div id="puzzle1-result"></div>
<div>
#Html.ActionLink("Back to List", "Index")
</div>
*Notice I removed the scripts section, you should have this in your layout instead.
MainView
#{
ViewBag.Title = "Puzzles 1 & 2";
}
<h2>#ViewBag.Title</h2>
<div>
#Html.Partial("Puzzle1Form")
</div>
<script>
$(document).ready(function() {
$(document).on('submit', '#frmPuzzle1', function(e) {
// stop default form submission
e.preventDefault();
$.ajax({
url: '#Url.Action("Puzzle1", "Puzzles")',
type: 'POST',
data: $('#frmPuzzle1').serialize(),
success: function(html) {
$('#puzzle1-result').html(html);
}
});
});
});
</script>
The Ajax.* family of helpers simply add a standard HTML setup (a regular old form, for example) and some JavaScript that intercepts the default behavior, sending it as AJAX instead. In other words, the code is unobtrusive. If for whatever reason the JavaScript can't be run, it will fallback to standard behavior of doing a simple form post.
Therefore, if it's doing a standard form post, rather than sending an AJAX request, you most likely have some JavaScript error on the page that is preventing the AJAX code from running.
The Ajax.* family of helpers simply add a standard HTML setup (a regular old form, for example) and some JavaScript that intercepts the default behavior, sending it as AJAX instead. In other words, the code is unobtrusive. If for whatever reason the JavaScript can't be run, it will fallback to standard behavior of doing a simple form post.

Submit send values null in Ajax to Controller

I have several ajax.begin form within a Ajax.BeginForm "father".
The problem to the "parent" function or the first Ajax.BeginForm need to put another empty begin.form, but depending on the way place or father sends "nulls" information or the first Ajax.BeginForm send a submit to the Ajax.BeginForm "father".
my code :
#using (var f = Html.Bootstrap().Begin(new Form("","").Id("").HtmlAttributes(new { ReturnUrl = Request.QueryString["ReturnUrl"] })))
{
using (Ajax.BeginForm("", "", new AjaxOptions { }))
{
}
using (#Ajax.BeginForm("SaveChanges", "Requests", null, new AjaxOptions { HttpMethod = "POST" }, null))
{
using (Ajax.BeginForm("", "", new AjaxOptions { }))
{
}
using (#Ajax.BeginForm("AddMoney","Requests", null, new AjaxOptions { HttpMethod = "POST" }, null))
{
<div class="row">
<div class="col-md-12">
<div class="box">
<div class="box-title">
<h3>
<i class="fa fa-bars"></i>Money</h3>
<div class="box-tool">
<label class="control-label">
</label>
<a data-action="collapse" href="#"><i class="fa fa-chevron-up"></i></a>
</div>
</div>
<div class="box-content">
<div class="row">
<div class="col-md-3">
<div class="form-group">
#f.FormGroup().TextBoxFor(_ => _.Money).Class("form-control").HtmlAttributes(new { mask = "999999999999" })
</div>
</div>
</div>
</div>
</div>
</div>
</div>
}
using (#Ajax.BeginForm("AddDate", "Request", null, new AjaxOptions { HttpMethod = "POST"}, null))
{
<div class="row">
<div class="col-md-12">
<div class="box">
<div class="row">
<div class="col-md-2" id="divDtFinalCorrecao" style="display: none;">
<div class="form-group">
#f.FormGroup().TextBoxFor(_ => _.date).Class("datepicker"))
</div>
</div>
</div>
</div>
</div>
</div>
}

How to pass an object using the Ajax.BeginForm() helper

I am trying to use the Ajax.BeginForm to post a message back to the server and I need to give a name to the form, i.e. use the parameter htmlAttributes. For that I am using the following signature:
#using (Ajax.BeginForm("SendEmail", "Contacts", null, new AjaxOptions { HttpMethod = "Post", UpdateTargetId = "sendMessageArea" }, new { Name = "sendEmail" }))
This code doestn't work, it updates the whole page and the controller is expecting an object as a paramenter:
public ActionResult SendEmail(Contacts contacts)
Here is the view:
<div class="row">
<div class="large-12 columns" >
#using (Ajax.BeginForm("SendEmail", "Contacts", null, new AjaxOptions { HttpMethod = "Post", UpdateTargetId = "sendMessageArea" }, new { Name = "sendEmail" }))
{
<fieldset class="form-group">
<legend>Leave a message</legend>
<div class="panel">
<div class="row">
<div class="large-offset-2 large-8 columns">
<div class="row">
<div class="large-2 columns">
<div class="form-group">
#Html.LabelFor(model => model.Name, new { #class = "control-label" })
</div>
</div>
<div class="large-8 columns">
#Html.TextBox("Name", Model.Name, new { placeholder = "Your name..." })
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="large-2 columns">
</div>
</div>
<div class="row">
<div class="large-2 columns">
<div class="form-group">
#Html.LabelFor(model => model.EMail, new { #class = "control-label" })
</div>
</div>
<div class="large-8 columns">
<div class="form-group">
#Html.TextBox("EMail", Model.EMail, new { placeholder = "Your email..." })
#Html.ValidationMessageFor(model => model.EMail)
</div>
</div>
<div class="large-2 columns">
</div>
</div>
<div class="row">
<div class="large-2 columns">
<div class="form-group">
#Html.LabelFor(model => model.Message, new { #class = "control-label" })
</div>
</div>
<div class="large-8 columns">
#Html.TextArea("Message", Model.Message, new { placeholder = "Your message here...", #class = "comment-control", id = "message" })
#Html.ValidationMessageFor(model => model.Message)
</div>
<div class="large-2 columns">
</div>
</div>
<div class="row">
<div class="large-offset-8 large-3 columns">
<input type='submit' style='position:absolute;top:0;left:-9999px;width:1px;height:1px' />
<a class='submit-button' href="javascript:sendEmail.submit()">
<span class='submit-button-inner'>Submit</span>
</a>
</div>
</div>
</div>
<div class="large-2 columns">
</div>
</div>
</div>
</fieldset>
}
</div>
and the partial view:
<span class="success label">#Resources.Contacts.Index.SuccessSendMessage</span>
I think the problem should be related with the routeValues parameter because if I use a simple example without the htmlAttributes and routeValues it works well.
Any guess?

Ajax GET request calling POST instead (ASP.NET MVC5)

I've created an ajax GET call to perform a search feature. But every time the search button is clicked, it is calling the POST instead (thereby returning null error for the model). I am not sure what I have done wrong. Care to give a hand please?
My controller:
//
// GET: /DataEntry/ChargeBack
public ActionResult ChargeBack(string dwName, string searchTerm = null)
{
var model = createModel();
if (Request.IsAjaxRequest())
{
return PartialView("_Suppliers", model);
}
return View(model);
}
//
// POST: /DataEntry/ChargeBack
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ChargeBack(ChargeBackViewModel model)
{
if (ModelState.IsValid)
{
model.someAction();
}
return View(model);
}
My Main View:
#model CorporateM10.Models.ChargeBackViewModel
#using (Ajax.BeginForm(
new AjaxOptions
{
HttpMethod = "get",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "SuppliersList"
}))
{
#Html.AntiForgeryToken()
<input type="search" name="searchTerm" class="form-control col-md-2" />
<input type="submit" value="Search by Name" class="btn btn-info" />
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true)
#Html.Partial("_Suppliers", Model)
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
My Partial View:
#model CorporateM10.Models.ChargeBackViewModel
<div class="form-group" id="SuppliersList">
<div class="col-md-10">
#Html.EditorFor(model => model.Suppliers)
#Html.ValidationMessageFor(model => model.Suppliers)
</div>
</div>
I've found it. It is being caused by not including jquery.unobtrusive-ajax library. Once included, the Ajax action works as intended.

Ajax.BeginForm routing to new page instead of a partial view

I have a Ajax.BeginForm call that is supposed to return a partial view but is rerouting the page to the Action instead. Any ideas on what is wrong?
Here is the code on the main page that I want to render the partial view on:
<div class="col-md-6">
#using (Ajax.BeginForm("Search", "Home", new AjaxOptions
{
HttpMethod = "GET",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "searchResults"
}))
{
<div class="form-group" style="width:85%;">
<div class="right-inner-addon">
<i class=" glyphicon glyphicon-search"></i>
<input type="text" data-autocomplete="#Url.Action("Quicksearch","Home")" class="form-control" placeholder="Search" name="q" />
</div>
</div>
<div class="form-group">
<button class="btn btn-default form-inline" type="submit">Search</button>
</div>
}
<br />
</div>
</div>
<div id="searchResults">
</div>
Here is the Partial view (items removed due to length):
<div class="row" id="searchResults">
...removed form elements
<div class="row">
<table class="table">
....stuff
</table>
</div>
</div>
Here is the controller:
public PartialViewResult Search(string q)
{
var items = db.items_with_descriptions
.Where(r => r.name.Contains(q) || string.IsNullOrEmpty(q))
.Take(10);
return PartialView("_Items", items);
}
As stated above, when I click my search button it redirects to localhost:24942/Home/Search instead of staying on the page and simply loading the partial view. I am new to MVC, so please keep that in mind. :)
The jquery-unobtrusive js file has to be included in your page to make the ajax.beginform work

Resources