Formatting currency using display template in MVC
X

2

9

I found this post about Display and EditorTemplates for MVC:

http://www.growingwiththeweb.com/2012/12/aspnet-mvc-display-and-editor-templates.html

It creates a display template to easily display a decimal formatted with currency sign.

The model used in the example:

public class TestModel
{
    public decimal Money { get; set; }
}

The display template:

Views/Shared/DisplayTemplates/decimal.cshtml:

@model decimal

@{
    IFormatProvider formatProvider = 
        new System.Globalization.CultureInfo("en-US");
    <span class="currency">@Model.ToString("C", formatProvider)</span>
}

In my website I have a helper class with a method to retrieve a formatted currency string from a decimal, so I would replace the above with something like:

@model decimal
@(MyHelperClass.GetCurrencyString(Model))

And finally the view where we want to see the formatted currency:

@model TestModel    
@Html.DisplayFor(e => e.Money)

Output:

<span class="currency">$3.50</span>

I can implement this without any problem. But of course i have different views where i want to view a formatted currency. But in some cases I don't want to show the currency sign.

My question now is how i should implement this small variation without to much overkill in code.

Here is my current implementation:

I've changed my display template to this:

@model decimal

@{
    bool woCurrency = (bool)ViewData["woCurrency"]; 
 }

@(MyHelperClass.GetCurrencyString(Model)Model,woCurrency))

Of course i've also changed to GetCurrencyString method to accept this additional attribute.

In my view I now have to provide this attribute too:

@Html.DisplayFor(m => m.Money, new { woCurrency = true })

So actually I everything works like it should work. But somehow I don't like this sollution that makes the view more complex.

My question to you: Is there any other method to implement something like this? Or any advice to possible optimise my current sollution?

Thanks!

Xenophobe answered 3/6, 2013 at 6:20 Comment(0)
S
2

How about HtmlHelper that checks the ViewData["woCurrency"] automatically and outputs the correct result?

    public static string Currency(this HtmlHelper helper, decimal data, string locale = "en-US", bool woCurrency = false)
    {
        var culture = new System.Globalization.CultureInfo(locale);

        if (woCurrency || (helper.ViewData["woCurrency"] != null && (bool)helper.ViewData["woCurrency"]))
            return data.ToString(culture);

        return data.ToString("C", culture);
    }

Then:

@Html.Currency(Model.Money);
Sombrero answered 3/6, 2013 at 6:35 Comment(6)
Thanks for the suggestion. Does this means i always need to set the property in the viewdata in the view? Since i have the multiple prices i want to show in one view but not all of them should show a currency sign. When i started reading about display templates i thought they would make everything much easier and cleaner, but it look like they fooled me :(Xenophobe
You can set ViewData in the controller as well.Sombrero
Yes i know, but then it would have the same value for every currency i want to format on the current view. I have a viewmodel representing a line in the basket. One of the properties is a decimal Price. For most lines i don't want a currency sign, for subtotal and total lines, i do want to show the currency sign. However both lines use the same object (viewmodel) to store their values.Xenophobe
Is your ViewModel contains a SubTotal and Total properties?Sombrero
Hmm.. not really. I was genarating a collection of cartlines on the model. Also a line for total, and subtotal. But you made me realise i could just create seperate properties for these and apply another template to those using the MVC data attribute UIHint. Now i have 2 display temlates: decimal.cshtml and Currency.cshtml. The last one will be used if i use [UIHint("Currency")]. For properties without this data attribute the default decimal formatting will be used without currency symbol as defined in decimal.cshtmlXenophobe
Yes, that was going to be my next step.Sombrero
T
18

You need to apply DisplayFormat attribute to your Money property. For example:

[DisplayFormat(DataFormatString = "{0:C}")]
public decimal Money { get; set; }

For more information have a look at these two links:

  1. DisplayFormatAttribute.DataFormatString (The example at the bottom of the page uses currency formatting as an example)
  2. ASP.NET MVC - DisplayFormat attribute
Topsyturvy answered 3/6, 2013 at 6:34 Comment(1)
Unfortunatly, we have some custom rules to format the currency string... This would also effect the rendering of my currency on every place it is used while i just want to make two different implementations.Xenophobe
S
2

How about HtmlHelper that checks the ViewData["woCurrency"] automatically and outputs the correct result?

    public static string Currency(this HtmlHelper helper, decimal data, string locale = "en-US", bool woCurrency = false)
    {
        var culture = new System.Globalization.CultureInfo(locale);

        if (woCurrency || (helper.ViewData["woCurrency"] != null && (bool)helper.ViewData["woCurrency"]))
            return data.ToString(culture);

        return data.ToString("C", culture);
    }

Then:

@Html.Currency(Model.Money);
Sombrero answered 3/6, 2013 at 6:35 Comment(6)
Thanks for the suggestion. Does this means i always need to set the property in the viewdata in the view? Since i have the multiple prices i want to show in one view but not all of them should show a currency sign. When i started reading about display templates i thought they would make everything much easier and cleaner, but it look like they fooled me :(Xenophobe
You can set ViewData in the controller as well.Sombrero
Yes i know, but then it would have the same value for every currency i want to format on the current view. I have a viewmodel representing a line in the basket. One of the properties is a decimal Price. For most lines i don't want a currency sign, for subtotal and total lines, i do want to show the currency sign. However both lines use the same object (viewmodel) to store their values.Xenophobe
Is your ViewModel contains a SubTotal and Total properties?Sombrero
Hmm.. not really. I was genarating a collection of cartlines on the model. Also a line for total, and subtotal. But you made me realise i could just create seperate properties for these and apply another template to those using the MVC data attribute UIHint. Now i have 2 display temlates: decimal.cshtml and Currency.cshtml. The last one will be used if i use [UIHint("Currency")]. For properties without this data attribute the default decimal formatting will be used without currency symbol as defined in decimal.cshtmlXenophobe
Yes, that was going to be my next step.Sombrero

© 2022 - 2024 — McMap. All rights reserved.