51

HTML5 appears to support a new range of input fields for things such as:

  • Numbers
  • Email addresses
  • Colors
  • URLs
  • Numeric range (via a slider)
  • 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)
4
  • What's the meaning of "typesafe" for the examples you share here? I can see the difference in both codes, but I don't get why one is typesafe and the other one is not. Commented Apr 19, 2022 at 14:18
  • @carloswm85 the first snippet uses an anonymous type. It's not typesafe because the compiler doesn't check the names of any of the properties. You could mistype min as man and your code would compile correctly but not produce the desired result, because of a typing error. If it were typesafe, this error would be caught. Commented Apr 23, 2022 at 12:43
  • So that happens in the first snippet because it is taking an object such as new { type="number", min="0", max="100" } as the second parameter? That's why it is not typesafe. Unlike the second snippet, where parameters are orderly set and described in, let's say, "individual parameters". Commented Apr 25, 2022 at 11:02
  • Yes, that's right. The compiler doesn't validate anything about new { ... }. Commented Apr 28, 2022 at 1:31

6 Answers 6

54

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; }
}
Sign up to request clarification or add additional context in comments.

2 Comments

@Drew - believe date, datetime and time are included in that work item (they are certainly part of mvc4 release). why do you say otherwise?
I misinterpreted the comment: We need to do this automatically for tel, url, email, datetime, date, time, and number. I've linked to the docs and extended the sample code. Nice find, thanks.
23

Check out the ASP.net MVC HTML5 Helpers Toolkit

1 Comment

doesn't MVC support HTML5 by deafault?
15

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 = ""
    })

5 Comments

That's pretty much what I show in the original question. I was looking for a more typesafe solution.
Hi @Drew - your are completely right, by the time i read the answers I had forgotten your original question - sorry!
No worries. Your code definitely works, but I would like to avoid using anonymous types, both for performance and because they're not checked by the compiler for correctness.
This answer definitely worth being here. Googled this question up - found this solution
This is the answer I found most easy to implement. I didn't want to have to use Editor helper, and this answer supports that inclination.
11

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> 

3 Comments

FYI, you can in fact use html attributes with EditorFor, but you would have to write your own template for it. Which is a lot less intrusive than writing a new Html helper.
I agree with u and i did see a few remarks about using templates. Sadly i'm only at the learning stage in MVC right now and didn't take the time to look at Editor and Display templates.
As of MVC 5.1 you can use HTML attributes with EditorFor tags.
9

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;)

1 Comment

In my case not working with TextBoxFor and EditorFor in both of IE and Chrome, What is the wrong you think?
2

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!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.