How can I add a class attribute to Html.BeginForm() in MVC3/4 preserving the minimal overload - asp.net-mvc-3

I'm in the process of upgrading my app to Bootstrap 2.1.1 and I need to add a class attribute (class="form-horizontal") to many of the form tags. The problem is, most of the forms use the rather beautiful
#using (Html.BeginForm()) {
format which I'd rather keep. The obvious way to get the class attribute in there is to use the following overload, for example:
#using (Html.BeginForm("Register", "Account", FormMethod.Post, new { #class = "form-horizontal" })) {
But I'd rather not do that. What is the best way to add a class attribute to my form?
I've thought about using a jQuery document ready handler to .addClass("form-horizontal") to forms, but am worried that users would see the dreaded 'flash of unstyled content'.
Another approach might be to use a less-style mix-in, to add the .form-horizontal class to all form style rules but I haven't used less yet, so I'm not sure about this one.
Anyone know the best way to solve this problem?

Following StanK's advice, and the advice of some other answers on SO, I created an extension method specifically tailored to that Bootstrap form layout:
public static MvcForm BeginHorizontalForm(this HtmlHelper helper) {
return helper.BeginForm(null, null, FormMethod.Post, new { #class = "form-horizontal" });
}
which allows me to use
#using (Html.BeginHorizontalForm()) {...
which is nice and elegant.

What about writing a custom helper method which calls the overload required, passing in 'form-horizontal'?
Then, you views would use #using (Html.BootstrapBeginForm()) {, leaving you views nice and tidy.

Related

Add jQuery Mobile transition to ASP.Net MVC Form

How does one add a jQuery Mobile transition to an HTML POST rendered with the ASP.Net MVC Html.BeginForm helper?
The transition requires an HTML attribute data-transition be added (I think to the form tag, but the docs are unclear on that point, providing only a hyperlink example).
I'm trying to use the BeginForm overload to add attributes to the rendered form tag. When using the new { ... } syntax to declare an anonymous class representing the HTML attributes, I get an error if an attribute name has a dash in it.
using (Html.BeginForm("Login", "Account", FormMethod.Post,
new { data-transition="pop" }))
Error: Invalid anonymous type member declarator
This, in spite of the fact that the MSDN documentation shows an attribute with a dash in the name
new { id = "text1", accept-charset="iso-8859-1" }
Create a dictionary:
using (Html.BeginForm("Login", "Account", FormMethod.Post,
new Dictionary<string, object>{{ "data-transition", "pop" }} ))
If you prefer to use an anonymous object to specify your attributes then you could do the following
using (Html.BeginForm("Login", "Account", FormMethod.Post, new { data_transition = "pop" } ))
In short you replace the hypen with an underscore

Use DELETE form method in Html.BeginForm()?

I'd like to use the appropriate HTTP method when possible. In this case, when a button is clicked to delete something, I want to fire the controller action with the attribute [HttpDelete]. However, I can't seem to create a form with this method - using Razor syntax. The FormMethod enum does not have an option for Delete and doing the following doesn't override it:
#using (Html.BeginForm("Order", "Users", FormMethod.Post, new { method = "DELETE" }))
Searching for solutions yields none, is nobody doing this? I know I can just use POST but isn't this the point of the HTTP delete method to begin with?
You need this in your form:
#using (Html.BeginForm("Order", "Users"){
#Html.HttpMethodOverride(HttpVerbs.Delete)
}

Loading multiple controls in ASP.NET MVC

I am creating my first site in asp.net MVC and I have a very beginner question in my mind. i have seen that in controller we are returning the actionview for what we want to display in the page [Most of the example in the websites I can see they are only displaying the content in the page] . What if I have to load 3 drop down list, 2 tables , 2 radio buttons etc. What is the best practice and the correct way to load these many controls on the page?
Chris
It sounds like you are expecting to use controls like one does in ASP.Net Web Forms. However, with MVC the View consists of standard HTML. The controls you mention can just be input select and so on. There are various helper classes and methods that you can use in the view to help you render the HTML you need - In particular take a look at the Razor syntax.
I'd start with looking at a couple of examples, and it should be clearer....
Here's a good one: http://www.nerddinner.com/ (source code here http://nerddinner.codeplex.com/)
Maybe pick up a couple of books from Amazon as well.
HTH
Phil
The examples you typically see use MVC's scaffolding, which creates a very simple Controller/Actions/Views to manipulate a certain Model class. But you're free to show anything you want in your pages. Here's an example on how to show a drop down list.
First create an object that will hold all the stuff you want to display on the page:
public class GameDetailsViewModel
{
public Game Game { get; set; }
public SelectList Players { get; set; }
}
Note the SelectList. It will be used as the source for the DropDownList.
Then the Action fills in this object:
public ViewResult Details(int id)
{
GameDetailsViewModel viewModel = new GameDetailsViewModel();
viewModel.Game = db.Games.Single(g => g.ID == id);
IEnumerable<Player> players = db.Players();
viewModel.Players = new SelectList(players, "ID", "FullName");
return View(viewModel);
}
Note the overload to the View() method, that takes the object we created to package the stuff we need on the page.
Then on the View, you can use an HtmlHelper to render a DropDownList:
#using (Html.BeginForm("signup", "games", FormMethod.Post))
{
#Html.DropDownList("playerID", Model.Players, "Select...", null)
<input type="submit" value="Sign up" />
}
This is a very simple example, but you can extend it to send whatever you want to the View and then render it using plain old HTML or the handy HtmlHelpers.

Rewriting Html.BeginForm() in MVC 3.0 and keeping unobtrusive javascript

This is going to seem like a bit of a silly endeavor, but it's something I want to learn nonetheless.
Right now, in ASP.NET MVC 3.0, you need to use the syntax #using (Html.BeginForm()) { and then later, the } to close a form block to get the fancy new 'unobtrusive javascript', lest you want to write all of it by hand (which is fine).
For some reason (Read: *OCD*) I don't like that. I'd really rather do this..
#Html.BeginForm()
<div class="happy-css">
</div>
#Html.EndForm()
Seem stupid yet? Yeah, well to each their own. I want to understand why it is working how it is and mold it to my liking. So I thought the first place I would start digging is the MVC 3.0 source itself. So I jumped into codeplex to find the BeginForm Extension method.
( http://aspnet.codeplex.com/SourceControl/changeset/view/63452#288009 )
So now I am a little confused as to how to begin achieving my goal. Reading through the code, I discovered that they all go down to a root method (not surprising, as most extension methods seem to be hierarchical methods all reaching down into a single one to avoid redundancy).
private static MvcForm FormHelper(this HtmlHelper htmlHelper, string formAction, FormMethod method, IDictionary<string, object> htmlAttributes) {
TagBuilder tagBuilder = new TagBuilder("form");
tagBuilder.MergeAttributes(htmlAttributes);
// action is implicitly generated, so htmlAttributes take precedence.
tagBuilder.MergeAttribute("action", formAction);
// method is an explicit parameter, so it takes precedence over the htmlAttributes.
tagBuilder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method), true);
HttpResponseBase httpResponse = htmlHelper.ViewContext.HttpContext.Response;
httpResponse.Write(tagBuilder.ToString(TagRenderMode.StartTag));
return new MvcForm(htmlHelper.ViewContext.HttpContext.Response);
}
What I am not seeing here is how this method relates to the unobtrusive javascript. If I simply type out ..
<form action="/Controller/Action" method="post">
and then put in my validation like so...
#Html.ValidationSummary(false)
I do not get the unobtrusive javascript. But if I use
#using (Html.BeginForm()) { then I do. I've even examined the generated markup and I really can't find the difference.
Now then it gets strange. If I just type in ...
#Html.BeginForm() and then put all of my form code, the form works and I get the unobtrusive javascript, but I have to manually type in </form> at the end. #Html.EndForm() doesn't work. But ontop of that, I now get the text System.Web.Mvc.Html.MvcForm written to the output stream right beneath the <form action="/Controller/Action" method="post"> html.
Can someone enlighten and/or help me?
The answer to your underlying question (i.e. how to use BeginForm/EndForm syntax) is to do it in the following manner:
#{ Html.BeginForm(...); }
<div> content</div>
#{ Html.EndForm(); }
Unfortunately the Razor syntax right now is a bit more verbose when invoking helpers that write to the output (as opposed to the majority of helpers which just return an html snippet). You could probably make this easier by writing your own extension methods like so:
public static IHtmlString FormBegin(this HtmlHelper helper, ...) {
helper.BeginForm(...);
return new HtmlString("");
}
public static IHtmlString FormEnd(this HtmlHelper helper) {
helper.EndForm();
return new HtmlString("");
}
The reason it works I believe is that the BeginForm method returns an MvcForm object and not html, it writes the html directly to the page. When the using block ends it is disposed and it writes the closing end tag. That's the reason you see the text System.Web.Mvc.Html.MvcForm appear in your output. You have to put the closing tag in there manually because the MvcForm object isn't disposed.
The using syntax is like doing this:
#{ MvcForm mf = Html.BeginForm(); /* writes directly to html stream */ }
<div class="happy-css">
</div>
#{ mf.Dispose(); /* like calling mf.EndForm() */ }

ASP.Net MVC 3 EditorTemplate for DateTime Fields Error

This code was converted from some ASP.Net MVC 2 code in this tutorial:
MVC 2 Editor Template with DateTime
It is a custom EditorTemplate for DateTime fields stored as 'EditorTemplates/DateTime.cshtml'.
#Model DateTime?
#Html.TextBox("", (Model.HasValue ? Model.Value.ToShortDateString() : string.Empty), new { #class = "datePicker" })
However I get the following error when using #Html.EditorFor(model => model.NewAbsence.StartDate):
CS1973: 'System.Web.Mvc.HtmlHelper' has no applicable method named 'TextBox' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax.
I've seen some similar posts on here which mention casting the parameter of the EditorFor method, however I cannot seem to get this to work in my example.
Could someone please point out what I will need to change in my code. Thanks.
Actually it's #model with lowercase m:
#model DateTime?
^
instead of:
#Model DateTime?
So to sort of summarize what people are saying, and make it a bit more generic. If your view is declaring that it accepts dynamic models:
#model dynamic
Then things like extension methods will not be able to infer the types of arguments passed to them. Here are two examples (using Razor because it's awesome):
#Html.TextBox("myTextBoxName", Model.MyTextBoxValue)
#Html.DropDownList("myDropDownName", Model.MySelectList))
In these cases, the engine doesn't know what types Model.MyTextBoxValue or Model.MySelectList are, therefore it can't figure out what overloads of the extension methods to compile. So you just help it along with some strong typing:
#Html.TextBox("myTextBoxName", (string)Model.MyTextBoxValue)
#Html.DropDownList("myDropDownName", (SelectList)Model.MySelectList))
By the way, just to stop people from potentially pulling out their hair, that SelectList has to be properly instantiated with something like:
var items = List<SelectListItem>();
...
new SelectList(items, "Value", "Text");
As a temporary work around I am using:
<div class="editor-field date-field">
#Html.EditorFor(model => model.NewAbsence.StartDate)
#Html.ValidationMessageFor(model => model.NewAbsence.StartDate)
</div>
Then using the jQuery selector:
$(".date-field > input").datepicker({
showOn: "button",
buttonImage: "*pathtoimage*"
});
To apply the date picker to the input tags within the 'date-field' div. However this still doesn't format the date value how I want it to display initially, and cuts out the editor template entirely.
The error message comes from your textbox statement. In a template, this becomes a dynamic expression, and .Net doesn't know how to type the Model properties.
#Html.TextBox("", (string)(Model==null ? Model.Value.ToShortDateString() : string.Empty), new { style = "width: 10em;", #class="datefield" })
Explicitly cast your date value as string, and the dynamic expression has the information it needs. I also had a problem with the .HasValue property, but that wasn't the point of your question.

Resources