MVC 4 Ajax.beginform submit - causes full postback - asp.net-mvc

MVC4 Internet project
I'm using Ajax.BeginForm to do a Postback with validation and it posts back the entire page rather than just the UpdateTargetID. I've looked at other posts on SO and haven't found the answer. I've built a new MVC4 Internet project just for testing (VS 2012 has been updated with 'ASP.NET and Web Tools 2012.2').
Here's my code
Controller
public ActionResult Index()
{
var vM = _db.Students.FirstOrDefault(); return View(vM);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(Student vM)
{
if (ModelState.IsValid)
{ //code if Model valid
return Json(new { url = Url.Action("About", "Controller") });
}
ModelState.AddModelError(string.Empty, "AJAX Post");
return PartialView("Index", vM);
}
View
#model AJAX_Test.Models.Student
#{ ViewBag.Title = "Student"; }
<script src="~/Scripts/jquery-1.8.2.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
<script type="text/javascript"> var onSuccess = function (result)
{
if (result.url) { window.location.href = result.url; }
}
// when server returns JSON object containing an url property redirect the browser </script>
<h1>#ViewBag.Title</h1>
<div id="IDXForm">
#using (Ajax.BeginForm("Index", new AjaxOptions() { UpdateTargetId = "IDXForm", OnSuccess = "onSuccess", HttpMethod = "Post" }))
{
#Html.AntiForgeryToken() #Html.ValidationSummary(true)
<span>#Html.EditorFor(m => m.FirstName) #Model.EnrollmentDate.ToShortDateString()</span> <input type="submit" value="Submit" />
}
</div>
The initial view is:
After Submittal:
Source code for body after submittal:
<div id="body">
<section class="content-wrapper main-content clear-fix">
<script src="/Scripts/jquery-1.8.2.js"></script>
<script src="/Scripts/jquery.unobtrusive-ajax.js"></script>
<script type="text/javascript"> var onSuccess = function (result) { if (result.url) { window.location.href = result.url; } }
// when server returns JSON object containing an url property redirect the browser </script>
<h1>Student</h1>
<div id="IDXForm">
<form action="/" data-ajax="true" data-ajax-method="Post" data-ajax-mode="replace" data-ajax-success="onSuccess" data-ajax-update="#IDXForm" id="form0" method="post"><input name="__RequestVerificationToken" type="hidden" value="vkCszJu-fKT6zUr5ys2StOTPF6a9pZdj5k1MyaAZKo8MPweS53dUuni0C9B17NjL_GVydHa7-jI1H0F9HrYEdKxeCWq9mCeER3ebaZYLxIs1" /><span><input class="text-box single-line" id="FirstName" name="FirstName" type="text" value="Carson" /> 9/1/2005</span> <input type="submit" value="Submit" />
</form></div>
Can anyone see what is wrong with my code?
Thank you.

A couple of things that come to mind that might be causing this behavior:
In your question you have shown your bundle registrations but have you actually included them in your view or Layout? Make sure that in your view or layout you have first included jquery.js and then jquery.unobtrusive-ajax.js (in that order):
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryval")
The jquery.unobtrusive-ajax.js script is not compatible with jquery 1.9 and later because it relies on the .live() which has been removed in jQuery 1.9. So if for some reason you have upgraded your jQuery version to 1.9 or later that won't work. You should downgrade.
In your onSuccess callback you are redirecting to an url if the controller action returns a JSON. Have you verified that this is not the case? Because when a redirect happens using the window.location.href it's pretty normal that you get a full page reload and not a partial update
In all cases use a javascript debugging tool to see what exactly is happening. If you are using Firefox, then you could use FireBug. If you are using Google Chrome, you could use the Chrome Developer Toolbar. Look at the console for potential javascript errors you might have. Look at the network tab to see whether all javascripts are successfully loaded and you don't have 404 errors. Learn how to debug your javascript code with a tool. You will be surprised how much information about potential issues you might have with your code those tools will provide you.

The contents of the UpdateTargetID must be in a partial view and that partial view needs to be called from the Controller Post Action. Darin answered me through e-mail (thank you Darin). You need to use a parital view. I've tried to update his answer twice and the moderators have not done it or provided an explanation why so I'm posting my own answer for others benefit.
_MyForm View:
#model AJAX_Test.Models.Student
#using (Ajax.BeginForm("Index", new AjaxOptions { UpdateTargetId = "IDXForm", OnSuccess = "onSuccess" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<span>
#Html.EditorFor(m => m.FirstName) #Model.EnrollmentDate.ToShortDateString()
</span>
<input type="submit" value="Submit" />
}
Main View :
<div id="IDXForm">
#Html.Partial("_MyForm")
</div>
Controller Post Action:
ModelState.AddModelError(string.Empty, "AJAX Post");
return PartialView("_MyForm", vM);

use:<script src="../Scripts/jquery.unobtrusive-ajax.js"></script>
This JS is what makes Ajax work.

Couple of other things to note.
jquery.unobtrusive-ajax.js now supports JQuery 1.9. I have installed jquery.unobtrusive-ajax.js version 3.0.0 and it is working with JQuery 1.9
2. Make sure all the div tages are closed properly, including the view which contains the Ajax.BeginForm and the main view. Also if you have #Html.Raw() in the main view or inside the view which contains Ajax.BeginForm be cautious about that too.
Posting here to save one day of head scratching.

make sure you have your bundles config include this
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery.unobtrusive*",
"~/Scripts/jquery-{version}.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.validate*"));

At a minimum, you need these two includes:
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryval")
And if that still does not help, check in web.config and make sure unobtrusive is enabled:
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
And if that still has no effect, make sure unobtrusive js files are compatible with current jQuery version, whatever version of jQuery you are using, which can be found at a below URL:
http://www.nuget.org/packages?q=unobtrusive

Related

Asp.net MVC button does not show

I place a button in a div tag, and when I run it, I only see the div container
<div style= "border-style:solid;border-width:1px; padding:5px; background-color:#ffffcc">
<asp:button ID = "refresh" runat ="server" OnClientClick="reloadPage()">
<script type="text/javascript">
function reloadPage(){
window.location.reload()
}
</script>
</asp:button>
</div>
the refresh button is nowhere can be found. Are there anything wrong with my code? I am new to MVC, please give me suggestions.
Why are you using asp controls in an MVC project -> use an HTML element.
Use a Form
<div>
#using (Html.BeginForm("Action", "Controller", FormMethod.Post))
{
<button type="submit">Submit</button>
}
</div>
Use a Button
<div>
<button onclick="DoSomeJavascript" >Submit</button>
</div>
MVC uses Controllers (Code Behind) and Views (Html) to create pages. To send data to or from a page you need to use View Models.
Maybe have a look at this handy guide: http://www.asp.net/mvc/overview/getting-started/introduction/getting-started
Your question states that you are new to MVC, yet you are trying to define a button from classic ASP.NET, which will not be processed by the Razor view engine used by MVC. Since you are just reloading the page you can do this with regular HTML buttons and Javascript. I'm not reloading the page here in this snippet, but that's irrelevant.
<div style="border-style:solid; border-width:1px; padding: 5px; background-color:#ffffcc">
<button id="refresh" onclick="reloadPage()">
Refresh Page
<script type="text/javascript">
function reloadPage() {
console.log("Reloaded")
//Reload page here
}
</script>
</button>
</div>
If you run this and click you should see the log message in your Javascript console.

Why Html.BeginForm in MVC4 is affected by the button click event,does it happen in MVC5?

My web page have a button and a form,I use #Html.BeginForm to produce the form and when I click the button,I will jump to the login page.To my surprise,when I click the button,the form post to my controller automatically.But when I use #using (Html.BeginForm,it seems OK.
My web page
<button onclick="logout()">logout</button>
#Html.BeginForm("ExportFile", "Student", new { id = "exportForm" }))
{
#Html.Hidden("year")
#Html.Hidden("fileName")
}
My new web page will work well
<button onclick="logout()">logout</button>
#using (Html.BeginForm("ExportFile", "Student", new { id = "exportForm" })))
{
#Html.Hidden("year")
#Html.Hidden("fileName")
}
I find the different HTML is System.Web.Mvc.Html.MvcForm):
<form id="exportForm" method="post" action="/Student/ExportFile">
System.Web.Mvc.Html.MvcForm) {
<input id="year" type="hidden" value="" name="year">
<input id="fileName" type="hidden" value="" name="fileName">
}
What is the difference between then?Someone teach me to add #{Html.EndForm();} when I using #Html.BeginForm,but it seems not work.May be it works in MVC3.
You can use these two methods only if you add the button type.
<button onclick="logout()" type="buttton">logout</button>
The using statement automatically adds the closing tag for the form's HTML. You should always use #using if you are using Html.BeginForm().

ASP.NET : Textbox OnTextChanged MVC refresh whole page

I'm having a trouble while devolping my .net application.
I'm using the event OnTextChanged on a textbox to change the content in another Textbox, the first textbox has AutoPostBack="true", but when i write in it and click in another part, the page refreshes completely.
here is my ascx code:
<form id="Form1" runat="server">
Change text
<asp:TextBox id="txt1" runat="server" ontextchanged="ejemplo" autopostback="true"/>
<p><asp:Label id="lbl1" runat="server" /></p>
</form>
and the script in the same ascx page:
<script runat="server">
protected void ejemplo(object sender, EventArgs e)
{
lbl1.Text = "Changed";
}
</script>
I'm using MVC4,
Thanks for your answers.
EDIT:
here is a video of what is really happening:
http://remainedesign.com/video/asd.html
Life cycle of MVC and webforms both are different.
MVC is not about server controls.... viewstate... no page life cycle events in web form...
What is the 'page lifecycle' of an ASP.NET MVC page, compared to ASP.NET WebForms?
hope this helps..
Now coming to your point.
if you want to display something in the Textbox2 while entering a Value into the Textbox1 you have to use client side script, see example below
javascript
<script type="text/javascript" language="javascript">
function textCounter(field, field2, maxlimit) {
var countfield = document.getElementById(field2);
if (field.value.length > maxlimit) {
field.value = field.value.substring(0, maxlimit);
return false;
} else {
countfield.value = maxlimit - field.value.length;
}
}
</script>
Your Html page
<%using (Html.BeginForm("Index", "Account", FormMethod.Post)) // here index is a ActionName, Account is a controller name
{%>
<input type="text" id="textbox1" name="Message" onkeyup="textCounter(this,'textbox2',208)"/>
<input disabled maxlength="3" size="3" value="208" id="textbox2" /></label>
<input type="submit" value="Send" />
<%}%>
Here
textCounter() function on keyup event in textbox1 will display value in textbox2,
submit button will submit form which call action "index" on controller "Account",see below how action act
public class AccountController : Controller
{
[HttpPost]
public ActionResult index(FormCollection result)
{
string TextBoxValue=result["Message"];
return view("yourviewname");
}
}
please note,above example is solely for MVC project
i hope this example may help you..
the first textbox has AutoPostBack="true", but when i write in it and
click in another part, the page refreshes completely
That is exactly what AutoPostBack is for. If you click on another part, that's when you lose focus on the textbox and it will trigger a postback. If you need more proof then read this from MSDN:
Gets or sets a value that indicates whether an automatic postback to
the server occurs when the TextBox control loses focus.

calling an AJAX method from an ASP.NET MVC 2 view

I want to know how to use Ajax in MVC2. I created an empty project in Visual Studio and added a home controller under Controllers/Home/HomeController.cs with the following code
How do I use AJAX to call the AjaxTest method on the HomeController when the button is clicked and display that text instead?
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult AjaxTest()
{
return Json("Whoever answers this rocks!");
}
}
I added a view under Views/Home/Index.cs with the following code
<script type="text/javascript">
function sayHello() {
alert("hello stackoverflow :)")
}
</script>
<div>
Hello
<button onclick="sayHello();"> Click Me! </button>
</div>
This should work:
<script type="text/javascript">
function sayHello() {
$.get('/Home/AjaxTest', function(data) { alert(data) });
}
</script>
Remember to include jQuery in head section of your page:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
You can also include jQuery in scripts folder of your project. jQuery is a part of ASP.NET MVC framework files.
EDIT:
Change your action to
public ActionResult AjaxTest()
{
return Json("Whoever answers this rocks!", JsonRequestBehavior.AllowGet);
}
By default, using Json with get results in "This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet." error.
Don't forget that the <button> element submits the form by default, which may cause unintended effects on your AJAX calls. Consider <input type="button" value="Click Me" /> or returning false in your sayHello() function.

Nerd dinner error on Ajax call to Register action method

I'm new to MVC and I'm implementing the Nerd Dinner MVC sample app in MS MVC2. I'm on step 10, "Ajax enabling RSVPs accepts". I've added the new RSVP controller and added the Register action method like so:
public class RSVPController : Controller
{
DinnerRepository dinnerRepository = new DinnerRepository();
//
// AJAX: /Dinners/RSVPForEvent/1
[Authorize, AcceptVerbs(HttpVerbs.Post)]
public ActionResult Register(int id) {
Dinner dinner = dinnerRepository.GetDinner(id);
if (!dinner.IsUserRegistered(User.Identity.Name)) {
RSVP rsvp = new RSVP();
rsvp.AttendeeName = User.Identity.Name;
dinner.RSVPs.Add(rsvp);
dinnerRepository.Save();
}
return Content("Thanks - we'll see you there!");
}
}
I added the references to both Ajax script libraries and added the code below to the Details view as described in the article:
<div id="rsvpmsg">
<% if(Request.IsAuthenticated) { %>
<% if(Model.IsUserRegistered(Context.User.Identity.Name)) { %>
<p>You are registred for this event!</p>
<% } else { %>
<%= Ajax.ActionLink( "RSVP for this event",
"Register", "RSVP",
new { id=Model.DinnerID },
new AjaxOptions { UpdateTargetId="rsvpmsg"}) %>
<% } %>
<% } else { %>
Logon to RSVP for this event.
<% } %>
</div>
When I click the "RSVP for this event" link I get a 404 eror saying the resource cannot be found:
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /NerdDinner/RSVP/Register/24
Version Information: Microsoft .NET Framework Version:2.0.50727.4200; ASP.NET Version:2.0.50727.4205
When I step into the code it is finding the Register action method correctly. After playing around with it I removed the "AcceptVerbs(HttpVerbs.Post)" from the constraint on the Register method, and it then worked. However it didn't reload the page it just displayed the "Thanks - we'll see you there" message on a new blank page. Looking at the html in the details page there is no Form submit taking place, so I'm wondering does the Ajax code need something more to make the call a Post? Is there a known issue with this part of the Nerd Dinner app? I think the app was written in MVC1 and I'm using MVC2 - does this make a diference?
TIA,
Ciaran
The PDF tutorial (versus the online HTML version) has typographic ANSI quote characters (0x94) rather than ASCII (0x22) in the HTML block of script elements. The correct block is shown below with all of the quote characters replaced.
<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>
Visual Studio will mark the JavaScript source files with the Warning green squiggles ("File not found") but not the type attributes so you may notice and correct the problem only for the source files. However, the type attributes will still be malformed and this will cause the scripts not to be loaded correctly in the browser.
Using the Chrome developer tools, I noticed that the scripts were not listed as Resources for the Details HTML page. Correcting the quote characters for the type attributes allowed the Register action to work as documented in the tutorial with no changes.
This portion of your action explains why you just get the "see you there" message:
return Content("Thanks - we'll see you there!");
That's all that's being returned.
The reason you were getting a 404 to begin with is the use of an actionlink:
Ajax.ActionLink(...
That will create a URL link, a GET not a POST, and the AcceptVerbs(HttpVerbs.Post) would have forced no match. You should submit a form to do a post:
using (Ajax.BeginForm("Controller", "Action", new AjaxOptions { UpdateTargetId = "f1" } )) { %>
<div id="f1">
<!-- form fields here -->
<input type="submit" />
</div>
<% } %>
As an additional comment to debugging issues with this problem, being a Java/JSF developer, I ran into a hard lesson that
<script src="/Scripts/MicrosoftAjax.js" type="text/javascript" />
and
<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
are processed differently. The first not working at all and the second working correctly.
This is the Details.cshtml used in MVC3. The problem with redirecting using GET, and not POST is similar.
<div id="rsvpmsg">
#if (Request.IsAuthenticated)
{
if (Model.IsUserRegistered(Context.User.Identity.Name))
{
<p>
You are registered for this event</p>
}
else
{
#Ajax.ActionLink("RSVP for this event",
"Register",
"RSVP",
new { id = Model.DinnerID },
new AjaxOptions { UpdateTargetId = "rsvpmsg", HttpMethod = "Post" })
}
}
else
{
<p>
Logon to RSVP for this event.</p>
}
</div>
#section JavaScript
{
<script src="#Url.Content("~/Scripts/MicrosoftAjax.js")" type="text/javascript"></script>;
<script src="#Url.Content("~/Scripts/MicrosoftMvcAjax.js")" type="text/javascript"></script>;
}
Ok, so previously i have mentioned that i had the same problem, and it comes from the fact that MVC 3 uses unobtrusive JavaScript.
To make this work, you have 2 solutions, one is to disable Unobtrusive Javascript in your webconfig file:
<appSettings>
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
Just set it to false, and during page build, javascript generated for the Action link will be normal inline javascript, that works fine, and results with something like this in HTML:
<a onclick="Sys.Mvc.AsyncHyperlink.handleClick(this, new Sys.UI.DomEvent(event),
{ insertionMode: Sys.Mvc.InsertionMode.replace, httpMethod: 'Post', updateTargetId: 'rsvpmsg' });" href="/RSVP/Register/13">RSVP for this event</a>
Second solution is more to my liking and it is just as simple. You just have to include additional javascript source file in your header:
<head>
<title>#ViewBag.Title</title>
<link href="#Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
#RenderSection("JavaScript",required:false)
</head>
The resulting javascript generated is unobtrusive, and results with this in HTML:
RSVP for this event
In both cases the resulting functionality is the same, and the second solution is "more in spirit" of new MVC 3.
Just in case it helps someone else, i had the problem using MVC 3 and it was because I had linked to the MS AJAX libraries and MVC 3 actually uses jQuery by default so I just needed to uncomment the links in my master page and it was fine.
To make an http post with Ajax.ActionLink , you'd have to do e.g. new AjaxOptions { UpdateTargetId="rsvpmsg",HttpMethod="POST"}
if you include those two in your site.master, it should be fine
<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>
I was trying to convert to MVC3/Razor as I worked through this example. I've been stuck on this exact same issue for at least 24 hours now...exact same symptoms. I tried everything on this page that I could understand or thought was relevant.
I didn't have the unobtrusive javascript mention in my web.config and was considering adding it with the "false" value thinking "true" might be the default. However, I was thinking it might screw something else up (among who knows what else).
I found the following tid-bit over on the wrox forum. If I add the following line of code to the second line of my RSVPStatus.cshtml partial view:
<script src="/Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>
Everything works as intended. I know Zak mentioned that line of code above (and a bunch of other stuff that lead me in the right direction), but I was using the partial view and haven't seen a head tag since I started messing with MVC. I know it's probably there somewhere, but all the smoke and mirrors of what is MS programming now, makes it harder to dissect and I probably would have gone down Zak's path at some point. So, +1 for him.
Anyway, hope this helps someone save a day.

Resources