Check out the Alchemist's Edition

#60: Formatting Numbers

Phoenix 1.3

Number 0.5.6

View code on GitHub


Sign up for our newsletter to get notified when new episodes drop

If you’ve worked in web development you’ve probably had to convert numbers into different formats at some point. And if you’ve come from a web framework like Ruby on Rails you’ve probably used something like the NumberHelper module to do it.

These types of conversions don’t have a similar functions build into the Phoenix framework, but we have a great library - Number - to help us out.

Number provides different functions to help us convert numbers into different formats. The Number library is broken into a few different modules based on the type of conversion you aim to do.

Now let’s take a look at what we need to format. Here we have an app that let’s people list different Albums they have for sale. We can see how much each album is priced at. The popularity of the album. We also have the sellers contact info, including the phone number. Let’s format these different values to make them a little more user friendly. The first thing we’ll need to add Number to our list of dependencies.

mix.exs

defp deps do
...
{:number, "~> 0.5.6"},
...
end

Then we’ll go to the command line and download our dependency.

$ mix deps.get

Now that we have the Number package installed, let’s start by formatting the album price. Let’s go to our album_view.ex then let’s define a new function to format our album price. Right now our album price is stored as cents in the database, so let’s call our function cents_to_dollars and it will take our price.

Looking at the docs for the Currency module we see there’s a function number_to_currency that we can use format our number. It has a few different options like the unit, precision, and delimiter that we can provide it, but for our pricing the defaults will work just fine. We’ll call Number.Currency.number_to_currency passing in our price.

lib/teacher_web/views/album_view.ex

defmodule TeacherWeb.AlbumView do
  use TeacherWeb, :view

  def cents_to_dollars(price) do
    Number.Currency.number_to_currency(price)
  end

end

Now let’s go to our album’s index.html.eex and call our new function, passing in our our album’s price.

Template path: lib/teacher_web/templates/album/index.html.eex

...
<td><%= cents_to_dollars(album.price) %></td>
...

And let’s start the server:

$ mix phx.server

Back in our browser we see that while our prices are being formatted, they’re not correct. This is because we are just passing in our price in cents to be formatted. We need to convert it to dollars before.

So let’s back back to our album_view.ex and we’ll fix it by dividing our price by 100. Then piping the result into the number_to_currency function.

lib/teacher_web/views/album_view.ex

...
def cents_to_dollars(price) do
  price / 100 |> Number.Currency.number_to_currency()
end
...

We’re also displaying our pricing on the album’s show.html.eex template, so let’s open that, and update our price here as well.

Template path: lib/teacher_web/templates/album/show.html.eex

...
<strong>Price:</strong>
<%= cents_to_dollars(@album.price) %>
...

Then if we go back to the browser - perfect, our album prices are now displaying correctly.

Now let’s update how we’re formatting the popularity of an album. Currently we are displaying a popularity calculation from the database. Let’s use the Number.Percentage.number_to_percentage function to make it a little prettier and display a rounded percentage along with the percent symbol instead of spelling it out.

We’ll go back to our album_view.ex and create another helper function, we’ll call popularity_as_percent and it will take our album’s popularity. And call Number.Percentage.number_to_percentage.

lib/teacher_web/views/album_view.ex

...
def popularity_as_percent(popularity) do
  Number.Percentage.number_to_percentage(popularity)
end
...

Then let’s go to our album’s show.html.eex template and call our new function. We can also remove the word “percent” since our new function will render the percent symbol for us.

Template path: lib/teacher_web/templates/album/show.html.eex

...
<li>
  <strong>Popularity:</strong>
  <%= popularity_as_percent(@album.popularity) %> of users like this album.
</li>
...

And if we go back to the browser we see our popularity is now being formatted with a percent. However, the default is to display our percentage with three decimal places. Let’s update it to not show any decimal places.

We’ll go back to our album_view.ex and update our function to include the precision option of zero.

lib/teacher_web/views/album_view.ex

...
def popularity_as_percent(popularity) do
  Number.Percentage.number_to_percentage(popularity, precision: 0)
end
...

Going back to our browser, we see our percentage is formatted with no decimal places displayed. Now let’s take care of the final piece of formatting for the page - the contact number.

To format it we’ll use the Number.Phone module. Let’s go to our album_view.ex and we’ll create another helper function called display_phone_number that will take our phone number to format.

Then we’ll call Number.Phone.number_to_phone passing in the phone number. Let’s also include the area code true option, since our number are stored with the area code in the database. And instead of a dash for the delimiter, let’s just use a space.

lib/teacher_web/views/album_view.ex

...
def display_phone_number(phone_number) do
  Number.Phone.number_to_phone(phone_number, area_code: true, delimiter: " ")
end
...

Now we’ll update our show.html.eex to pass our phone number into our new helper function.

Template path: lib/teacher_web/templates/album/show.html.eex

...
<p>
  <b>Phone:</b>
  <%= display_phone_number(@seller.phone_number) %>
</p>
...

We’ll go back to the browser. And great - we see our phone number is displaying. Our fields are now displaying with their updated formatting.