ASP.NET MVC HTML helper methods for new HTML5 input types
HTML5 appears to support a new range of input fields for things such as:
- Numbers
- Email addresses
- Colors
- URLs
- Numeric range (via a slider) 开发者_如何学C
- Dates
- Search boxes
Has anyone implemented HtmlHelper
extension methods for ASP.NET MVC that generates these yet? It's possible to do this using an overload that accepts htmlAttributes
, such as:
Html.TextBoxFor(model => model.Foo, new { type="number", min="0", max="100" })
But that's not as nice (or typesafe) as:
Html.NumericInputFor(model => model.Foo, min:0, max:100)
Just a heads up that many of these are now incorporated into MVC4 by using the DataType
attribute.
As of this work item you can use:
public class MyModel
{
// Becomes <input type="number" ... >
public int ID { get; set; }
// Becomes <input type="url" ... >
[DataType(DataType.Url)]
public string WebSite { get; set; }
// Becomes <input type="email" ... >
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
// Becomes <input type="tel" ... >
[DataType(DataType.PhoneNumber)]
public string PhoneNumber { get; set; }
// Becomes <input type="datetime" ... >
[DataType(DataType.DateTime)]
public DateTime DateTime { get; set; }
// Becomes <input type="date" ... >
[DataType(DataType.Date)]
public DateTime Date { get; set; }
// Becomes <input type="time" ... >
[DataType(DataType.Time)]
public DateTime Time { get; set; }
}
Check out the ASP.net MVC HTML5 Helpers Toolkit
Easiest way is to simply add type="Email" as an html attribute. It overrides the default type="text". Here is an example with a html5 required validator also:
@Html.TextBox("txtEmail", "",
new { placeholder = "email address",
@type="email",
@required = ""
})
What i don't like about DataTypes Attributes is that u have to use EditorFor in the view. Then, you can't use htmlAttributes to decorate your tag. There are other solutions but i prefer this way.
In this example i only extended the signature i use the most.
So in the class:
using System.Linq.Expressions;
namespace System.Web.Mvc.Html
{
public static class HtmlExtensions
{
public static MvcHtmlString EmailFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression, Object htmlAttributes)
{
MvcHtmlString emailfor = html.TextBoxFor(expression, htmlAttributes);
return new MvcHtmlString(emailfor.ToHtmlString().Replace("type=\"text\"", "type=\"email\""));
}
}
}
As you see i just changed the type="text" for type="email" and then i can use in my view:
<div class="form-group">
@Html.LabelFor(m => m.Email, new { @class = "col-lg-2 control-label" })
<div class="col-lg-10">
@Html.EmailFor(m => m.Email, new { @class = "form-control", placeholder = "Email" })
@Html.ValidationMessageFor(m => m.Email)
</div>
</div>
And the html source gives:
<div class="form-group">
<label class="col-lg-2 control-label" for="Email">Email</label>
<div class="col-lg-10">
<input class="form-control" data-val="true" data-val-required="The Email field is required." id="Email" name="Email" placeholder="Email" type="email" value="" />
<span class="field-validation-valid" data-valmsg-for="Email" data-valmsg-replace="true"></span>
</div>
</div>
Love it when can drive this type of stuff off the model!! I decorated my models with [DataType(DataType.PhoneNumber)]
, and all but one worked.
I realized the hard way that @Html.TextBoxFor
doesn't render the type="<HTML5 type>"
but @Html.EditorFor
does. Makes sense I guess now that I think about it, but posting this to maybe save others the frustrating few minutes that I just lost;)
I found my self wanting the number spinner you get when using <input type='number' />
from an HtmlHelper, and ended up solving it my self.
In a similar fashion to RPAlbert's Html.EmailFor answer above, I started off using the normal Html.TextBoxFor, but then I used LinqToXml to modify the HTML rather than just using a string replace.
The advantage of starting with the Html.TextBoxFor is that you can use of all the client side validation stuff that MVC does for you. In this case I am using the values from the data-val-range
attributes to set the min/max attributes needed to constrain the spinner.
public static HtmlString SpinnerFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object htmlAttributes)
{
XDocument _xml = XDocument.Parse(html.TextBoxFor(expression, htmlAttributes).ToString());
XElement _element = _xml.Element("input");
if (_element != null)
{
_element.SetAttributeValue("type", "number");
if (_element.Attribute("data-val-range-max") != null)
_element.SetAttributeValue("max", _element.Attribute("data-val-range-max").Value);
if (_element.Attribute("data-val-range-min") != null)
_element.SetAttributeValue("min", _element.Attribute("data-val-range-min").Value);
}
return new HtmlString(_xml.ToString());
}
You would then use it as you would any other HtmlHelper in your views:
@Html.SpinnerFor(model => model.SomeNumber, new { htmlAttribute1 = "SomeValue" })
This was my implementation of it anyway, from you question I can see that you wanted:
@Html.NumericInputFor(model => model.Foo, min:0, max:100)
It would be very simple to tweak my method to do this as follows:
public static HtmlString NumericInputFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, int min, int max)
{
XDocument _xml = XDocument.Parse(html.TextBoxFor(expression, htmlAttributes).ToString());
XElement _element = _xml.Element("input");
if (_element != null)
{
_element.SetAttributeValue("type", "number");
_element.SetAttributeValue("min", min);
_element.SetAttributeValue("max", max);
}
return new HtmlString(_xml.ToString());
}
Basically all I have done is to rename it and provide min/max as arguments rather than getting them from DataAnnotation attributes.
I hope that helps!
精彩评论