I just realized that when I place a form tag on my layout page, surrounding the RenderBody section, the unobtrusive validation is not being generated. Something like this:
@using (Html.BeginForm())
{
<input type="submit" value="save" />
<div>
@RenderBody()
</div>
}
As you might have guessed I want to generate buttons over my content. Is this the correct unobtrusive's behavior?
BTW, If I place the form inside a particular page, everything works like a charm: the data-val* attributes are well generated.
I'll appreciate your valuable help.
best regards
Rodrigo
You could apply a grotesque hack inside your view:
@{
var originalContext = ViewContext.FormContext;
ViewContext.FormContext = new FormContext();
}
<!-- This will generate proper HTML5 data-* validation attributes -->
@Html.TextBoxFor(x => x.Prop1)
@Html.ValidationMessageFor(x => x.Prop1)
@Html.TextBoxFor(x => x.Prop2)
@Html.ValidationMessageFor(x => x.Prop2)
@{
ViewContext.FormContext = originalContext;
}
While putting @using (Html.BeginForm())
into the content page fixes the validation problem it also puts an extra set of <form>
tags into the output. I created a small extension that fixes the problem without writing anything to the output.
Use it as @using (Html.BeginSubForm())
public static class FormExtensions
{
public static MvcSubForm BeginSubForm(this HtmlHelper html)
{
return new MvcSubForm(html.ViewContext);
}
}
public sealed class MvcSubForm : IDisposable
{
private readonly ViewContext _viewContext;
private readonly FormContext _originalFormContext;
public MvcSubForm(ViewContext viewContext)
{
_viewContext = viewContext;
_originalFormContext = viewContext.FormContext;
viewContext.FormContext = new FormContext();
}
public void Dispose()
{
if (_viewContext != null)
{
_viewContext.FormContext = _originalFormContext;
}
}
}
Thanks for your help, I tried it but I found a solution not as "grotesque" (as you said) as you suggested :D
I simply put a BeginForm method inside my page and also a BeginForm method on the layout:
@* On the layout page *@
@using (Html.BeginForm())
{
<input type="submit" value="save" />
<div>
@RenderBody()
</div>
}
@* On the content page *@
@using(Html.BeginForm())
{
@* Content *@
}
so, at the end I have two BeginForm methods: ASP.NET MVC engine is using the one located on the layout page, so the data-val* attributes are being rendered correctly and the form is placed just where I wanted so any submit button on the layout can submit my particular page with the validations rendered
It works pretty well
Thanks a lot
regards,
Rodrigo
I've just run into the same problem, but possibly a better solution based on Darin Dimitrov's answer.
The trick is to create a page base type, based on the WebViewPage<T>
class, the default base class for views and do the FormContext
swap there.
abstract public class FormFixWebViewPage : FormFixWebViewPage<object>
{
}
abstract public class FormFixWebViewPage<T> : WebViewPage<T>
{
override public void Write(System.Web.WebPages.HelperResult result)
{
var originalFormContext = ViewContext.FormContext;
ViewContext.FormContext = new FormContext();
base.Write(result);
ViewContext.FormContext = originalFormContext;
}
}
And then in the Web.config
file under the ~/Views/
folder, alter the pageBaseType
attribute under pages
element, which can be found in the system.web.webPages.razor
section:
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="<YOUR-NAMESPACE>.FormFixWebViewPage">
<!--pages pageBaseType="System.Web.Mvc.WebViewPage"-->
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Helpers" />
<add namespace="System.Web.Routing" />
</namespaces>
</pages>
</system.web.webPages.razor>
Just add below code at top of the child view file...
@{
Layout = "~/Views/Shared/_Layout.cshtml";
this.ViewContext.FormContext = new FormContext();
}
its working fine for me.
i hope this will help you....