Reputation: 605
I've looked around the web for a while, but can't find a good solution to my specific issue. I'm working on a MVC3 Razor app. I'm doing a bunch of stuff on the client side with jQuery as well so in this case I need my input fields to have html Id attributes.
In this specific issue when I use a TextBoxFor to display a currency (type is decimal), the value renders with 4 decimal places (I only want 2). I put in the model attribute
[DisplayFormat(DataFormatString = "{0:n2}", ApplyFormatInEditMode = true)]
When it renders it seems to ignore this "displayFormat". I've seen other posts online confirming that this problem exists with the TextBoxFor html helper.
On the other hand, I can change to use an EditorFor html helper and the DisplayFormat model attribute works for formats my textbox value to 2 decimal places. The down-side is I loose the ability to apply html attributes to my html helper which I need for jQuery. What is the best way to get the best of both worlds? I've seen a bunch of workarounds, but it seems like there must be an easier way to do this.
As a side note, my specific project requires most of my fields to have html Id attributes and sometimes classes so I can perform client side jQuery operations. Not sure if this means I should focus on extending the EditorFor html helper to also accept html attributes or not.
Upvotes: 4
Views: 3202
Reputation: 605
I ended up using Telerik's Numeric Textbox control. I'm sure both of the above answers would fix the decimal formatting.
I'm still need to circle back on the model validation. I was having problems with the EditorFor html helper pulling validation the data annotations on the model for validation while doing the same with a TextBoxFor was not. But at the same time the downside to the EditorFor helper didn't accept HtmlAttributes which I needed for jQuery.
I've started to use the MVC4 RC so I'm hoping many of these things are fixed in version 4.
Upvotes: 0
Reputation: 93424
The simple solution here is to create a custom display and editor template for your custom currency type. Do this.
public class MyModel {
[DataType(DataType.Currency)]
public decimal mycurrency {get;set;}
}
Then in ~/Views/Shared/EditorTemplates/Currency.cshtml (or DisplayTemplates)
@model decimal?
@Html.TextBox("", string.Format("{0:0.00}", Model), new { whateveryourattributes="attributevalues"})
Then you can just use DisplayFor or EditorFor or whatever.
Upvotes: 0
Reputation: 26689
DisplayFormat
is only used by MVC in any of the Display
extension methods for razor. (such as DisplayFor
) Unfortunately to do what you want you would have to write some "by hand" code...here's an example to get you going. It basically reproduces the TextBoxFor code but makes some assumptions that are most likely bad for production. Note the assignment of displayText
below, that's where we actually care about the DisplayFormatString
you set in your DisplayFormat
.
To call it in your view @Html.TextEditorFor(m => m.Value)
public static class CustomEditorFor
{
public static IHtmlString TextEditorFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
{
return TextEditorFor(helper, expression, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
}
public static IHtmlString TextEditorFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes)
{
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
object value = metadata.Model;
string displayText = string.Format(metadata.DisplayFormatString, value);
string fullName = helper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(ExpressionHelper.GetExpressionText(expression));
TagBuilder tagBuilder = new TagBuilder("input");
tagBuilder.MergeAttributes(htmlAttributes);
tagBuilder.MergeAttribute("type", "text");
tagBuilder.MergeAttribute("name", fullName, true);
tagBuilder.MergeAttribute("value", displayText);
tagBuilder.GenerateId(fullName);
ModelState modelState;
if (helper.ViewData.ModelState.TryGetValue(fullName, out modelState))
{
if (modelState.Errors.Count > 0)
{
tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
}
}
tagBuilder.MergeAttributes(helper.GetUnobtrusiveValidationAttributes(ExpressionHelper.GetExpressionText(expression), metadata));
return new HtmlString(tagBuilder.ToString(TagRenderMode.SelfClosing));
}
}
Upvotes: 2