When using a form like this:
<h2>
<%:Model.EulaTitle %>
</h2>
<p>
<%=Model.EulaHtml %>
</p>
<a name="errors"></a>
<%:Html.ValidationSummary()%>
<div style="text-align:center;">
<% using (Html.BeginForm())
{ %>
<%:Html.HiddenFor(model => model.SourceUrl)%>
<%:Html.HiddenFor(model => model.EulaId)%>
<a name="accept"></a>
<div style="text-align:center;">
<%:Html.CheckBoxFor(model => model.Accepted)%>
<%:Html.LabelFor(model => model.Accepted)%>
</div>
<input type="submit" value="Submit">
<% } %>
</div>
I need the page to scroll to #errors
when it posts. The Model.EulaHtml
contains some length EULA text and I'd prefer that the user not have to manually scroll down to see an error message if they post the page without accepting the agreement.
If the controller detects ModelState.IsValid
on Post, it redirects to another page. If not, I need to stay on this page, but scroll to the #errors
bookmark anchor tag.
I've thought about just adding '#errors' to the end of the url in the form action, but I receive errors along the line of a potentially dangerous .... ('%')
. It's possible that I'm incorrectly encoding the hash mark. Anyone else had to deal with this? We're dealing with pretty restrictive requirements for browser compatibility (IE6+ and everything else under the sun) so I try to avoid using JavaScript whenever possible.
Update
The error I'm receiving is:
A potentially dangerous Request.Path value was detected from the client (%).
I modifed the Html.BeginForm()
call to
<% using (Html.BeginForm(new { @action="#errors" }))
{ %>
And the resulting URL is:
http://..../TheControllerName/Eula/%2523errors/
I also noticed that a few queryString parameters that were being passed through disappear when I set the action
attribute in this way. (Not surprising, but no fix for that is immediately obvious to me)
Try like this:
<form action="<%: Url.Action("actionName", "controllerName") %>#errors" method="post">
<%:Html.HiddenFor(model => model.SourceUrl)%>
<%:Html.HiddenFor(model => model.EulaId)%>
<a name="accept"></a>
<div style="text-align:center;">
<%:Html.CheckBoxFor(model => model.Accepted)%>
<%:Html.LabelFor(model => model.Accepted)%>
</div>
<input type="submit" value="Submit">
</form>
You could also write a custom HTML helper that will do the job:
public static class FormExtensions
{
public static MvcForm MyBeginForm(this HtmlHelper htmlHelper, string actionName, string controllerName, string fragment)
{
var formAction = UrlHelper.GenerateUrl(null, actionName, controllerName, htmlHelper.ViewContext.HttpContext.Request.Url.Scheme, null, fragment, null, htmlHelper.RouteCollection, htmlHelper.ViewContext.RequestContext, true);
var builder = new TagBuilder("form");
builder.MergeAttribute("action", formAction);
builder.MergeAttribute("method", "post", true);
htmlHelper.ViewContext.Writer.Write(builder.ToString(TagRenderMode.StartTag));
return new MvcForm(htmlHelper.ViewContext);
}
}
And then:
<% using (Html.MyBeginForm("index", "home", "errors")) { %>
...
<% }
Updated MVC 4 solution to the problem:
@using (Html.BeginForm(null, null, null, FormMethod.Post,
new
{
@action = Url.Action("MyAction") + "#bookmark",
@class = "form-class",
target = "_blank"
}))
{
...
<input type="submit" value="submit" />
}
Html.BeginForm will generate the validation attributes in your form, using the html <form>
tag will not.
This call is using the Html.BeginForm(actionName, controllerName, routeValues, FormMethod, htmlAttributes)
overload, nulling all the routing and assigning the action as an html attribute instead. The routing is accomplished by using Url.Action(), to which I append my bookmark.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With