I have two properties in a model class:
public int? IntTest { get; set; }
public decimal? DecimalTest { get; set; }
Which I then render with:
@Html.EditorFor(model => model.IntTest, new { htmlAttributes = new { @class = "form-control"} })
@Html.EditorFor(model => model.DecimalTest, new { htmlAttributes = new { @class = "form-control"} })
I'd expected both of them to render as html inputs of type number, but the decimal one doesn't, I get:
<input class="form-control text-box single-line" data-val="true" data-val-number="The field IntTest must be a number." id="IntTest" name="IntTest" type="number" value="" />
<input class="form-control text-box single-line" data-val="true" data-val-number="The field IntTest must be a number." id="DecimalTest" name="DecimalTest" type="text" value="" />
The decimal value is rendered as type="text"
whereas the int is registered as type="number"
.
This question implies that isn't the expected behaviour so am I doing something wrong?
If that is the expected behaviour, is there any way of changing EditorFor
to render all decimals as type="number"
, rather than having to add type = "number"
in the htmlAttributes
of every decimal field?
The html you are seeing is the default behavior. The EditorFor()
methods use the default templates (unless you have created a custom EditorTemplate
for the type) as defined in TemplateHelpers.cs.
For typeof int
(and byte
and long
), it uses the NumberInputTemplate
, and for typeof decimal
it uses the DecimalTemplate
. These templates are defined in DefaultEditorTemplates.cs which are for decimal
internal static string DecimalTemplate(HtmlHelper html)
{
if (html.ViewContext.ViewData.TemplateInfo.FormattedModelValue == html.ViewContext.ViewData.ModelMetadata.Model)
{
html.ViewContext.ViewData.TemplateInfo.FormattedModelValue = String.Format(CultureInfo.CurrentCulture, "{0:0.00}", html.ViewContext.ViewData.ModelMetadata.Model);
}
return StringTemplate(html);
}
which in turn calls
internal static string StringTemplate(HtmlHelper html)
{
return HtmlInputTemplateHelper(html);
}
and for int
internal static string NumberInputTemplate(HtmlHelper html)
{
return HtmlInputTemplateHelper(html, inputType: "number");
}
Note that the NumberInputTemplate
defines the inputType
as "number"
which adds the type="number"
attribute, where as StringTemplate
uses the default inputType
which generates type="text"
.
To add type="number"
for a decimal
, then you need to manually add the attribute, using either
@Html.EditorFor(m => m.DecimalTest, new { htmlAttributes = new { type = "number", @class = "form-control"} })
or
@Html.TextBoxFor(m => m.DecimalTest, new { type = "number", @class = "form-control"})
An alternative would be to create a custom EditorTemplate
in the /Views/Shared/EditorTemplates/Decimal.cshtml
for typeof decimal
, for example
@model decimal?
@{
var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(ViewData["htmlAttributes"]);
if (!attributes.ContainsKey("type"))
{
attributes.Add("type", "number");
}
string formatString = ViewData.ModelMetadata.DisplayFormatString ?? "{0:N2}";
}
@Html.TextBoxFor(m => m, formatString , attributes)
and in the main view use
@Html.EditorFor(model => model.DecimalTest, new { htmlAttributes = new { @class = "form-control"} })
Another alternative would be to create you own HtmlHelper
extension method (say @Html.DecimalFor(...)
) to generate the html.