Ajax.BeginForm doesn't fire AJAX script, falls back on postback - ajax

I will update this problem with the solution, I wanted to include my problem and solution as I wasn't able to find it on Stackoverflow. If you want to jump in with the solution, feel free.
I have a newly created 'Empty' MVC5 project created using Visual Studio 2013. I needed a from and wanted AJAX behavior if possible. Using Ajax.BeginForm was always straight-forward in MVC3 so I thought it would be in MVC5 also.
However none of the javascript functions I've specified in OnBegin, OnFailure or OnSuccess inside the AjaxOptions are invoked when I click the submit button. Instead an Ajaxless post is sent to the server, this has shown to be true by examining Request.IsAjaxRequest which returns false.
I have concluded that for some reason, then, ajax isn't being used at all. I've checked a number of things such as web.config, my layout scripts, etc.
My layout includes the following scripts:
<script src="~/Scripts/jquery-1.5.1.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
My web.config includes:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
</configuration>
My view:
#model ContactEnquiryViewModel
#{
AjaxOptions ContactOptions = new AjaxOptions()
{
OnBegin = "OnConactFormBegin()",
OnSuccess = "OnContactFormSuccess()",
OnFailure = "OnContactFormFailure()"
};
}
<div id="EnquiryFormContainer">
#using (Ajax.BeginForm("Contact", "Home", new { formName = "EnquiryForm" }, ContactOptions))
{
#Html.HiddenFor(m => m.Subject)
<div class="field">
#Html.LabelFor(m => m.FirstName)
#Html.TextBoxFor(m => m.FirstName)
<div class="validation">
#Html.ValidationMessageFor(m => m.FirstName)
</div>
</div>
<div class="field">
#Html.LabelFor(m => m.LastName)
#Html.TextBoxFor(m => m.LastName)
<div class="validation">
#Html.ValidationMessageFor(m => m.LastName)
</div>
</div>
<div class="field">
#Html.LabelFor(m => m.Email)
#Html.TextBoxFor(m => m.Email)
<div class="validation">
#Html.ValidationMessageFor(m => m.Email)
</div>
</div>
<div class="field">
#Html.LabelFor(m => m.PhoneNumber)
#Html.TextBoxFor(m => m.PhoneNumber)
<div class="validation">
#Html.ValidationMessageFor(m => m.PhoneNumber)
</div>
</div>
<div class="field">
#Html.LabelFor(m => m.Comments)
#Html.TextAreaFor(m => m.Comments)
<div class="validation">
#Html.ValidationMessageFor(m => m.Comments)
</div>
</div>
<div id="submitButtonContainer">
<input type="submit" value="Submit" name="submit" />
</div>
}
</div>
My controller action (unfinished):
[HttpPost]
public ActionResult Contact(ContactViewModel viewModel, String formName = "")
{
if (Request.IsAjaxRequest())
{
return new EmptyResult();
}
return new EmptyResult();
}
I have checked some other posts on this problem, and couldn't find a solution. Though some hinted at the possible solution, I was confused by the Microsoft CDN (http://www.asp.net/ajaxlibrary/cdn.ashx).
On the Microsoft CDN they have the following section:
The following ASP.NET MVC JavaScript files are hosted on this CDN:
ASP.NET MVC 5.0
http://ajax.aspnetcdn.com/ajax/mvc/5.0/jquery.validate.unobtrusive.js
http://ajax.aspnetcdn.com/ajax/mvc/5.0/jquery.validate.unobtrusive.min.js
ASP.NET MVC 4.0
http://ajax.aspnetcdn.com/ajax/mvc/4.0/jquery.validate.unobtrusive.js
http://ajax.aspnetcdn.com/ajax/mvc/4.0/jquery.validate.unobtrusive.min.js
ASP.NET MVC 3.0
http://ajax.aspnetcdn.com/ajax/mvc/3.0/jquery.unobtrusive-ajax.js
http://ajax.aspnetcdn.com/ajax/mvc/3.0/jquery.unobtrusive-ajax.min.js
http://ajax.aspnetcdn.com/ajax/mvc/3.0/jquery.validate.unobtrusive.js
http://ajax.aspnetcdn.com/ajax/mvc/3.0/jquery.validate.unobtrusive.min.js
http://ajax.aspnetcdn.com/ajax/mvc/3.0/MicrosoftMvcAjax.js
http://ajax.aspnetcdn.com/ajax/mvc/3.0/MicrosoftMvcAjax.debug.js
ASP.NET MVC 2.0
http://ajax.aspnetcdn.com/ajax/mvc/2.0/MicrosoftMvcAjax.js
http://ajax.aspnetcdn.com/ajax/mvc/2.0/MicrosoftMvcAjax.debug.js
ASP.NET MVC 1.0
http://ajax.aspnetcdn.com/ajax/mvc/1.0/MicrosoftMvcAjax.js
http://ajax.aspnetcdn.com/ajax/mvc/1.0/MicrosoftMvcAjax.debug.js
They would seem to suggest the only script you'll need for MVC5 is jquery.validate.unobtrusive.

To get a local copy as part of your MVC project"
From VS2013, right click on your MVC 5 project, select "Manage NuGet Packages".
Select "Online" and search for "jquery.unobtrusive-ajax",
Then Install "Microsoft.jQuery.Unobtrusive.Ajax".

I had the same issue on a dummy MVC5 project.
Add this to your BundleConfig
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.unobtrusive*",
"~/Scripts/jquery.validate*"));
Add this to your layout.cshtml
#Scripts.Render("~/bundles/jqueryval")
I didn't add any new files to my projects so if you have an MVC 4 or 5 web project, I doubt if you would need to add any extra js files.
It solved my issue. I hope it solves yours.

Everything has started working since I included the following script in my layout:
<script src="http://ajax.aspnetcdn.com/ajax/mvc/3.0/jquery.unobtrusive-ajax.min.js"></script>
On the Microsoft CDN it looks as though this script is MVC3-specific.
Feel free to contribute better ways if possible, or answer the question: "Why isn't this script included in the MVC project template (VS2013)?"

Did you check if your web.config file contains
<appSettings>
<!-- this one is for client side validation -->
<add key="ClientValidationEnabled" value="true" />
<!-- this is for unobtrusive ajax -->
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>

I had the same issue and the solution was actually to make sure that the script references are in the right order (specifically that #Scripts.Render("~/bundles/jquery") appears before #Scripts.Render("~/bundles/jqueryval"))
For some reason it wasn't like it by default when creating the new project and adding the nuget packages

Adding reference to the javascript file jquery.unobtrusive-ajax.js worked for me.

For me it was a little bit peculiar and counter-intuitive.
The page was displayed from the controller with a custom route attribute:
[Route("contact")]
[HttpGet]
public ActionResult Contact()
{
return this.View();
}
but the POST action handling the AjaxRequest had no [Route("contact")] attribute and that's why it didn't work.

For me it was the way i posted the form:
Changing Submit
Into <button type="submit" value="">Submit</button> solved my problem.

Related

ASP.NET MVC 3 Ajax.BeginForm redirecting to new window

I'm trying to use an Ajax.BeginForm. When I submit, I want to render a partial view. Everything is working fine, but the InsertionMode = InsertionMode.Replace is not working, it opens the partial view in a new window.
I have also an Ajax.ActionLink in the same page, and that is working fine.
I have already added the jquery.unobtrusive-ajax.js and it still doesn't work. Also, in the web.config I have
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
Here is my code from the view:
<div id="div_to_replace">
#using (Ajax.BeginForm("Edit", "MyController", new AjaxOptions { HttpMethod = "POST", InsertionMode = InsertionMode.Replace, UpdateTargetId = "div_to_replace" })){
<div class="editor-field">
#Html.EditorFor(model => model.name)
#Html.ValidationMessageFor(model => model.name)
</div>
<input type="submit" value="Save" />
}
</div>
And my controller:
[HttpPost]
public ActionResult Edit(MyObject object)
{
try
{
if (ModelState.IsValid)
{
updateModel(object)
return PartialView("_MyPartilView", model);
}
else
{
return PartialView(object);
}
}
catch
{
return PartialView(object);
}
}
Thanks!
I have found the problem. I was using the last jquery version (1.9.1) and it doesn't work with the original jquery.unobtrusive-ajax.js file.
I changed to jquery version 1.4.4 (the one that comes by default when you create an asp.net mvc 3 project) and the problem was solved.
Make sure you have jQuery included.
Make sure you have a div with ID div_to_replace.
Make sure UnobtrusiveJavaScriptEnabled is active, on your web.config in Views folder
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>

Html.RenderPartial and Ajax.BeginForm -> Submit is called twice

I have the following index view:
#model BoringStore.ViewModels.ProductIndexViewModel
#{
ViewBag.Title = "Index";
}
<h2>Produkte</h2>
<div id='addProduct'>
#{ Html.RenderPartial("Create", new BoringStore.Models.Product()); }
</div>
<div id='productList'>
#{ Html.RenderPartial("ProductListControl", Model.Products); }
</div>
The "productList" is just a list of all products.
The addProduct renders my Create View:
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<div id="dialog-confirm" title="Produkt hinzufügen" style="display:none">
#using (Ajax.BeginForm("Index_AddItem", new AjaxOptions { UpdateTargetId = "productList" }))
{
#Html.Raw(DateTime.Now.ToString());
<div>
#Html.LabelFor(model => model.Name)
#Html.EditorFor(model => model.Name)
</div>
<br />
<div>
#Html.LabelFor(model => model.Price)
#Html.EditorFor(model => model.Price)
</div>
<br /><br />
<div>
<input type="submit" value="Produkt hinzufügen" />
</div>
}
When submitting the form, the Index_AddItem-method in my controller is called. Unfortunately the form always calls the method twice. :(
Can someone help me out?
Don't include scripts inside your partial views! They should go the your "main" views or your _layout.cshtml.
Your problem is that you have included the jquery.unobtrusive-ajax.min.js twice in your page. Once in your Create partial and once somewhere else. Because if you include that script multiple times it will subscribe on the submit event multiple times so you will get multiple submit with a single click.
So make sure that you have include that script only once in a page. So move the jquery.unobtrusive-ajax.min.js reference into your index view.
insure that you dont have jquery.unobtrusive-ajax.min.js file duplicated in the layout
as mentioned above, and you can check this using browser Inspectors
Another problem which may cause this error that i have encountered is resting a form using jquery in the ajax request as following
$("form").trigger("reset"); //just remove this line

Ajax in ASP.NET MVC3 Razor

I have a problem with Ajax.
I want to make multiple forms and replace div containing one after submiting with some Partial View. It's working for me when I use only one form. I don't know what I'm doing wrong here. Maybe it's becasue of custom editorfor?
Here is my code, plese try to help me, I've been trying do this for 2 days.
Index
#model MetriceWeb.Models.TaskInputModel
#{
ViewBag.Title = "Tasks";
}
<h3>
Tasks</h3>
#if (Model.Values.Count == 0)
{
<p>No pendings forms for you at the moment</p>
}
else
{
#Html.EditorFor(x => x.Values)
}
TaskInputValue (editorfor)
#model MetriceWeb.Models.TaskInputValue
#{string s = "task" + Model.TaskId;}
#using (Ajax.BeginForm("GetFromLibrary", "Metrice", new AjaxOptions
{
HttpMethod = "Get",
UpdateTargetId = s,
InsertionMode = InsertionMode.Replace
}))
{
<div class="editor-field" id="#s">
#Html.HiddenFor(x => x.TaskId, new { #class = "TaskId" , id = "TaskId" })
#Html.HiddenFor(x => x.InputId, new { #class = "InputId" })
<h2>
#Html.DisplayFor(x => x.Task)
</h2>
<span>Created: </span>
#Html.DisplayFor(x => x.Date)
<div>
Input Value
#Html.EditorFor(x => x.DateValue)
#Html.ValidationMessageFor(x => x.DateValue)
</div>
<input type="submit" value="Submit" />
</div>
<br />
}
It's entering method in my controller where I'm returning partial view. After submitting my div isn't replacing, the whole new site is loaded. What is wrong here? Please help me, I am in big need.
In order to the Ajax helpers like Ajax.BeginForm work correctly (e.g sending an AJAX request) you need reference in your view the following JavaScript file
jquery.unobtrusive-ajax.js
(and of course before that jquery)
From the Unobtrusive Ajax in ASP.NET MVC 3
An interesting note: since there is no actual JavaScript being emitted
when you use unobtrusive Ajax, if you forget to include one or the
other script, you won’t see any errors when attempting to submit the
Ajax request; it will simply behave like a non-Ajax request.

How to return a view from a partial view post to a Controller?

So I have a partial view "_Customer "with a text box and a save button. Currently, the partial view code, I have this:
#model CompositeViews.Models.Customer
#using (Ajax.BeginForm("Edit", "Customer", new AjaxOptions { HttpMethod = "Post", InsertionMode = InsertionMode.Replace, UpdateTargetId = "customerDiv" }))
{
<div id="customerDiv">
#Html.ValidationSummary(true)
<fieldset>
<legend>Customer</legend>
#Html.HiddenFor(model => model.CustomerId)
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<p><input type="submit" value="Save" /></p>
</fieldset>
</div>
}
the view lives withing a parent view called index (which also provides the model the partial view is dependent upon):
#model CompositeViews.ViewModels.CompositeViewModel
<h2>Index</h2>
#Html.Partial("_Customer", Model.Customer)
The parent view is named Index.cshtml and is fed by a simple controller action. When I click on the Save button in the partial view, it goes to the appropriate action on the appropriate controller, but I'm not too sure how to return the updated model data BACK into the partial view.
In all the examples out there, it's a form that does an async post, but the UpdateTargetId targets a that is then filled with some type of updated content. That seems pretty straight-forward and simple.
What I'm struggling with is how to return the same form, with the updated model information using the existing view (_Customer). Basically, it's a BeginForm which targets itself with the result from the controller action, not some other div that is not part of the form.
I'd like to NOT have to rebuild all the HTML by hand that the _Customer view does for me via the MVC framework and return that for rendering. I guess I'm stuck with the form in the partial view submitting the data to the controller, and then needing a way for that same view to re-draw itself on returning from the action method.
Any ideas?
I hope I got you right and you want to show your updated on post back.
In that case you can try this:
<div id="customerDiv">
#Html.RenderAction("Edit", "Customer", Model)
</div>
and put your #using (Ajax.BeginForm()) in Edit result.

The model item passed into the dictionary is of type... ut this dictionary requires a model item of type

I'm new to exploring MVC3 and came up with a problem.
I'm editing my Master view and want the login boxes to be visible on every page when a user isn't logged in. I've done this by using this code:
#if (Request.IsAuthenticated)
{
<text>Welcome <strong>#User.Identity.Name</strong>!
[ #Html.ActionLink("Log Off", "LogOff", "Account") ]</text>
}
else
{
Html.RenderPartial("../Account/LogOn");
}
This works when going to my normal Index method of the HomeController.
However, when going to the Index method of my NewsController I get the following error:
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[LeagueSite.Models.News]', but this dictionary requires a model item of type 'LeagueSite.Models.LogOnModel'.
I understand what the problem is but don't really know a sollution for it.
The view LogOn looks like this (standard MVC3 logon view):
#model LeagueSite.Models.LogOnModel
#{
ViewBag.Title = "Log On";
}
<h2>Login</h2>
<p>
Please enter your user name and password. #Html.ActionLink("Register", "Register") if you don't have an account.
</p>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#Html.ValidationSummary(true, "Login was unsuccessful. Please correct the errors and try again.")
#using (Html.BeginForm()) {
<div>
<fieldset>
<legend>Account Information</legend>
<div class="editor-label">
#Html.LabelFor(m => m.UserName)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.UserName)
#Html.ValidationMessageFor(m => m.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(m => m.Password)
</div>
<div class="editor-field">
#Html.PasswordFor(m => m.Password)
#Html.ValidationMessageFor(m => m.Password)
</div>
<div class="editor-label">
#Html.CheckBoxFor(m => m.RememberMe)
#Html.LabelFor(m => m.RememberMe)
</div>
<p>
<input type="submit" value="Log On" />
</p>
</fieldset>
</div>
}
`
Any tips/ideas?
Quick and dirty: instead of Html.RenderPartial use Html.RenderAction:
Html.RenderAction("LogOn", "Account");
and in the LogOn action of the Account controller ensure to return a PartialView or you will get a stack overflow and Cassini will crash:
public ActionResult LogOn()
{
return PartialView();
}
I think your "news" view has already a model associated to it.
maybe it starts like this?:
#model LeagueSite.Models.News
well, if so, if you are not passing a model to your partial view, then the framework assumes by default that the model for that partial is "LeagueSite.Models.News", which of course isn't what you want. You must pass the LogOnModel to your LogOn partial view like this:
Html.RenderPartial("../Account/LogOn", Model.ObjLogonModel);
this assumes that you have an instance of LogonModel into your "News" model. then you'll be able to handle the Logon action
regards

Resources