my question is simple.
This code works fine, like expected. Submitting form causes div update. But if I delete the first (empty) form, it won't work anymore. It's needed to be there to work well. Why? It's really annoying for me. Because I can't solve it.
<% using (Ajax.BeginForm(new AjaxOptions { })) { }%>
<% using(Ajax.BeginForm("UpdateForm", new AjaxOptions{UpdateTargetId="textEntered"})) { %>
<%= Html.TextBox("textBox1")%>
<input type="submit" value="Submit"/><br />
<span id="textEntered">Nothing Entered</span>
<% } %>
Hope you will help me. Cheers
EDIT: added full code
view:
<head runat="server">
<title>Index</title>
<script src="../../Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="../../Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>
</head>
<body>
<form runat="server" id="form1">
<p>
Page Rendered: <%= DateTime.Now.ToLongTimeString() %>
</p>
<span id="status">No Status</span>
<br />
<%= Ajax.ActionLink("Update Status", "GetStatus", new AjaxOptions{UpdateTargetId="status" }) %>
<br /><br />
<% using (Ajax.BeginForm(new AjaxOptions { })) { }%>
<% using(Ajax.BeginForm("UpdateForm", new AjaxOptions{UpdateTargetId="textEntered"})){ %>
<%= Html.TextBox("textBox1")%>
<input type="submit" value="Submit"/><br />
<span id="textEntered">Nothing Entered</span>
<% } %>
</form>
</body>
controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public string GetStatus()
{
return "Status OK at " + DateTime.Now.ToLongTimeString();
}
public string UpdateForm(string textBox1)
{
if (textBox1 != "")
{
return "You entered: \"" + textBox1.ToString() + "\" at " + DateTime.Now.ToLongTimeString();
}
return String.Empty;
}
}
but trust me, the code should work fine, it's made by tutorial.
EDIT2: okey, now it works according to comments. But, if there can't be form in another form, why it works with 3 forms?:) there is one "main" form, and my ajax form. doesn't work. if in "main" form are two ajax forms, it works. Huh?
Try to remove <form runat="server" id="form1"> and </form> from your code. Nested forms are not allowed in HTML.
I could not reproduce the same issue locally, so in order to investigate why exactly that happens, look at HTML source, debug your HTTP traffic with Fiddler, try that in different browsers etc.
I suspect that the browser in your case might recognise the second form as a closing tag for the first one, and that's why the third form worked. You can see that if you explore DOM elements tree created by your browser.
Related
I must not understand something fundamental about the aspx page processing cycle. Please take a look at this simple example below.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<div>
<form method="post">
<textarea name="someContent" cols="35" rows="15"></textarea>
<input type="submit"/>
</form>
</div>
</body>
</html>
<script runat="server">
public void Page_Load() {
// The httpMethod is always set correctly to "GET" or "POST"
String httpMethod = HttpContext.Current.Request.HttpMethod;
if(IsPostBack)
DoSomething();
else
DoSomethingElse();
}
</script>
Note the <form> element does not have a runat='server' attribute.
When the page is loaded for the first time, the Page_Load() fires and the httpMethod variable is set to "GET" and the IsPostback property returns false, all as expected.
When the user clicks the "submit" button, the Page_Load() fires again and the httpMethod variable is set to "POST", so the ASP.NET plumbing obviously knows this is a POST verb; however, the IsPostBack property still returns false. This seems odd to me. I would think that if the httpMethod was set to "POST", the IsPostBack would return true.
If I change the <form> element to contain a runat='server' attribute things change a bit. Now when the user presses the "submit" button the httpMethod variable is set to "POST", just as before, but now IsPostBack returns true.
Since I have no need to access the <form> element on the server, I saw no need to use a runat='server' attribute on it. But for some reason, the runat='server' must be present on the <form> in order for the IsPostBack to return a correct value, even though the HttpContext.Current.Request.HttpMethod property returns the correct value regardless of the runat='server' attribute.
Can anyone explain WHY the runat='server' is necessary on the <form> to make IsPostBack work correctly?
NOTE: Please note that I am not asking how to "do this" or "do that". My goal is to understand "The Why".
Thanks
Page checks few special fields (viewstate and postback event) to determine if request is postback or not.
http://referencesource.microsoft.com/System.Web/R/ae07c23d0aba6bb9.html
Both forms here cause IsPostBack to be true:
<%# Page Language="C#" AutoEventWireup="true" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<p><%= IsPostBack? "POSTBACK" : "NO POSTBACK" %></p>
<form id="form1" runat="server">
<input type="submit" />
</form>
<form id="form2" method="get">
<input type="hidden" name="__EVENTTARGET" value="" />
<input type="submit" />
</form>
</body>
</html>
Server-controlled form just adds and populates these fields automatically.
I have a MVC 3 application where I am using razor views. I have a SiteLayout.cshtml page, which is my master page for the site. Then, I have a Login.cshtml page which uses the SiteLayout.cshtml as the master page. I also have a _ViewStart.cshtml page that applies the master page to all cshtml pages.
I recently added a 'Forgot password' link to my login page. When I run the app, it doesn't show the new link. I cleaned the solution & rebuilt the solution, but that didn't help. Its almost like the razor views are getting cached. I checked all my browser settings (IE, Firefox, Chrome) to make sure that they are not caching.
I am totally stumped with this one. Any ideas??
Here is the code for the master page:
#using System.Web.UI.WebControls
#{
Layout = null;
}
<!DOCTYPE html>
<html lang="en">
<head runat="server">
<title>Application - #ViewBag.Title</title>
<script src="/Scripts/jquery-1.7.min.js" type="text/javascript"> </script>
<script src="/Scripts/jquery.tools.min.js" type="text/javascript"> </script>
<link rel="stylesheet" type="text/css" media="all" href="/Content/Site.css" />
</head>
<body>
<!-- Total width: 1180px -->
<div id="maincontainer">
<div id="header">
<span style="text-align:left; float:left;">Header</span>
<span style="text-align:right; float:right; width:200px;">#Html.Partial("LoginStatus")</span>
</div>
<div id="maincontent">
#RenderBody()
</div>
</div>
</body>
</Html>
Code for the login view:
#{
ViewBag.Title = "Login";
}
<div style="width:500px;">
#using(Html.BeginForm("Authenticate", "Account", FormMethod.Post))
{
<fieldset>
<legend>Login</legend>
<div class="errorMessage">#Html.ValidationMessage("LoginError")</div>
<label for="Email">Email</label>
#Html.TextBox("Email", string.Empty, new { #style = "width:250px;" })
<label for="Password">Password</label>
#Html.Password("Password", string.Empty, new { #style = "width:100px;" }) <br/><br />
<div class="buttons">
<button type="submit" class="positive" name="login">
<img src="/Content/images/lock_open.png" alt=""/>
Login
</button>
</div>
<p>#Html.ActionLink("Forgot Password?", "ForgotPassword", "Account")</p>
</fieldset>
}
</div>
Finally, code for _ViewStart:
#{
Layout = "~/Views/Shared/SiteLayout.cshtml";
}
Hit [control] + F5 to force a refresh.
Above each Action method you can set an output caching attribute for that page. Here is an article on it output caching
Alternatively you can set your caching preferences site wide in the web.config
Besides cleaning and rebuilding, which you mentioned you had done, You might want to check and make sure you don't have any instances of your .NET Development server running.
If you don't want caching to occur at all, you can use the following attribute to ensure that nothing is cached:
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]
//Your Controller Here
I think I have it figured out. I am sure it has something to do with the configuration of my machine since its not happening to others. So, instead of allowing VS2010 to assign its own port, I forced-picked a port. And I now get the new view.
I am pretty new to MVC. I have my first Ajax Form here:
<div id="test"></div>
<div id="MainChatMenu">
<% using (Ajax.BeginForm("SendMessage", "MainChat", new AjaxOptions { UpdateTargetId="test"}))
{ %>
<input id="chatMessageText" type="text" maxlength="200" />
<input type="submit" value="Go"/>
<% } %>
Now, if I click the submit button, the page is reloading, goint to mysite/controller/action.
I thought that the default behaviour of the Ajax.BeginForm was exactly not to do that?
Where's my newbie mistake?
My Controller is called correctly, but data passing also doesn't work. Probably because of the same mistake?
Here's the code:
public class MainChatController : Controller
{
[AcceptVerbs(HttpVerbs.Post)]
public EmptyResult SendMessage(FormCollection formValues)
{
return new EmptyResult();
}
}
Make sure you have included the necessary script libraries:
<script type="text/javascript" src="<%= Url.Content("~/scripts/MicrosoftAjax.js") %>"></script>
<script type="text/javascript" src="<%= Url.Content("~/scripts/MicrosoftMvcAjax.js") %>"></script>
<% using (Ajax.BeginForm("SendMessage", "MainChat", new{}, new AjaxOptions { UpdateTargetId="test", HttpMethod="POST"})) %>
I have multiple pages containing the same partial view. The partial contains a form that posts to an action. After a post I want to return to the page I was on before the post. What's the best way to do this?
Example:
Partial View:
form post action = note/create/
Pages
page1:
products/index/
page2:
customer/details/
page3:
order/details/
These 3 pages contain the partial view, when posting the partial it redirects to note/create/. I need to return to the original page on success.
Thanks
Simon
Either have the post happen via AJAX -- thus not leaving the page, or pass the current controller/action/id (or the Url as a whole) as parameters to the action that handles the post. See below for an example of the later.
<% using (Html.BeginForm(...)) { %>
<input type='hidden'
name='currentController'
value='<%= ViewContext.RouteData["controller"] %>' />
<input type='hidden'
name='currentAction'
value='<%= ViewContext.RouteData["action"] %>' />
<input type='hidden'
name='<%= ViewContext.RouteData["id"] %>' />
...rest of form...
<% } %>
or
<% using (Html.BeginForm( ...,
new { ReturnUrl = Url.Action( ViewContext.RouteData["action"],
ViewContext.RouteData ) }, ... )) { %>
....
<% } %>
You can store the current page address in a hidden field and send it with Post request.
In your partial view:
<script type="text/javascript">
var field = document.getElementById("currentPage");
field.value=document.location.href;
</script>
<form method="post" action="note/create/">
...
<input type="hidden" value="" id="currentPage" name="currentPage" />
</form>
Then retrieve the address of the hidden input and redirect the user to it.
In ASP.Net MVC, having a form more or less like this:
<% using (Ajax.BeginForm(new AjaxOptions() { OnSuccess="onSuccess"})) {%>
<p>
<label for="Comment">Comment:</label>
<%= Html.TextArea("Comment")%>
<%= Html.ValidationMessage("Comment", "*")%>
</p>
<p><input type="submit" value="Submit comment" /></p>
<% } %>
How can the onSuccess Javascript function know whether the result is another version of the form because it didn't validate, a comment as a div to add to the list of comments or a log in page that should be pop up for logging in?
You can define that in your returning JSON or whatever transport method you use?
Not sure if that's what you're looking for, but also: this is how the onSuccess function is called:
YourFunction(ajaxContext);
AjaxContext is defined as follows:
AjaxContext ajaxContext = new AjaxContext(request, updateElement, loadingElement, ajaxOptions.InsertionMode);
You should replace the code inside your ajax form with a new partial view, then you will return that partial view from your controller. The partial view would consist in:
<p>
<label for="Comment">Comment:</label>
<%= Html.TextArea("Comment")%>
<%= Html.ValidationMessage("Comment", "*")%>
</p>
<p><input type="submit" value="Submit comment" /></p>
This way, your partial view works just like a regular view.
Unfortunately there is no simple way to execute javascript as a response (since you are responding with a view). It would be easier if your response was a Json string, but in that case, you can't use the AjaxForm because the Json string would be rendered on screen as a result of submitting the form (and processing its response). This may work though (I haven't tried it):
<p>
<label for="Comment">Comment:</label>
<%= Html.TextArea("Comment")%>
<%= Html.ValidationMessage("Comment", "*")%>
</p>
<p><input type="submit" value="Submit comment" /></p>
<script type="text/javascript">
function processResponse(data){
// blah blah blah
}
processResponse(<%= ViewData["dataFromTheController"] %>);
</script>
Your could simply add different CSS classes to the root elements of your responses (for example .form, .comments, .login). And then (for example in jQuery):
var response = $(responseContent);
$('.form', response).each(function() {
// $(this) is form
});
$('.comments', response).each(function() {
// $(this) is comments
});
$('.login', response).each(function() {
// $(this) is login page
});
How can the onSuccess Javascript
function know whether the result is
another version of the form because it
didn't validate, a comment as a div to
add to the list of comments or a log
in page that should be pop up for
logging in?
The short answer is that it cannot unless you explicitly validate it. That's because JSON is transported as a string and when the client side Javascript gets the string.
For starters you should implicitly know what sort of object to expect. If you are calling an web service # Cars/List then you know the returned object will be a list of cars and you parse that appropriately in your client. You can run into errors which you should handle appropriately by retrying the request or logging them or showing an error message.
I would recommend you to use the jquery.form plugin, with this you can have a normal form to act like an ajax one, like this:
<script type="text/javascript">
// wait for the DOM to be loaded
$(document).ready(function() {
// bind 'myForm' and provide a simple callback function
$('#myForm').ajaxForm(function() {
alert("Thank you for your comment!");
});
});
</script>
<form id="myForm" action="comment.php" method="post">
Name: <input type="text" name="name" />
Comment: <textarea name="comment"></textarea>
<input type="submit" value="Submit Comment" />
</form>