Edit and Update using Elixir Money library

I’m using Elixir Money to handle my money integers. I have a form for creating a %Product{} which has a column defined as field :price, Money.Ecto.Amount.Type in the schema and add :price, :integer in the migration for postgres. Creating a new product is fine, but I’m encountering problems when I try to edit and update.

The Money library returns a struct for the field (ie %Product{:price => %Money{amount: 500, currency: :USD}}) so when you render the products/edit page, nothing shows up in the :price field and, even worse, if you submit the form without entering anything into the field it updates the column to null meaning you have to remember what it currently is, press the edit button to get to the form and then type the value into the field before you forget.

Before I start creating alternate changesets, routes and/or forms, is there any way to get the :price number_input field to interpret what is returned from the schema and render it normally on the edit form, keeping in mind that the /new route also renders the same form.html.eex?

You can manually set/convert the value for the field to a number by doing:
number_input f, :price, value: to_integer(input_value(f, :price)).

3 Likes

I think I just needed to type out my problem to get the gears spinning, here’s what I’ve learned:

The controller under the edit/2 function (assuming you’re using phoenix generators) sends you product: product in the render call. I was confused about how the form knew where to get the values from since there is no explicit @product variable being used anywhere in the form, phoenix seems to take care of that for you as long as you declare the corresponding field name.

So this was as simple as

<%= number_input f, :price, value: @product.price.amount %>

Thanks for your eyes :slight_smile:

1 Like

input_value(f, :price) is basically doing what you did with @product.price, but using the phoenix_html form handling and without additional assigns besides what you passed to the form (e.g. @changeset).

1 Like

It’s like magic :joy:

Good day!

I don’t understand how to let users choice currency. I add field like
<%= number_input p, :price, value: input_value(p, :price) %>
but i also need another input with currency (like USD, EUR and so on)
how to do it?

please help

1 Like

Add another input - e.g. a select field listing all currencies.

Thanks for your reply

How can i do it?

I have 1 field in model called ‘price’. It hold Money.Ecto.Map.Type. In my schema i map this field to the JSON (as described in documentation).

Now i have number input for amount. But how to map select field to the currency field in price?

Thanks again

…["price"]["amount"] for the name of the amount field and …["price"]["currency"] for the name of the currency field should work with the ecto types of ex_money.

Thank you very much for your reply

My team and I stumbled upon this thread in 2023 since we’re looking into using Elixir/Phoenix for a product rewrite, and were looking into using Money for handling currency. AFAIU, the auto-generated code for core component stuff has changed since 2019, but this is what ended up working for us:

<.simple_form>
  ...
  <.input
    field={{f, :total}}
    value={Money.to_decimal(Phoenix.HTML.Form.input_value(f, :total))}
    type="number"
    label="Total"
  />
  ...
</.simple_form>

The part that wasn’t immediately intuitive was whether there was a better way to just pass Money.to_decimal as a “type-cast” somewhere to the component, or whether it should just be passed in as the value to the <input>. Realistically, it’d probably make more sense to just extend the input core component to have a “currency” variant where the assign_new call has the Money.to_decimal call directly inside it.

2 Likes