Cast form fields back to original type in LiveView forms

On the initial render of a form in LiveView (or Phoenix, in general), the type of the input_value(form, field) is the same as the type of the field in the schema. When a user inputs a value, however, form fields are cast to a string and so the type of input_value(form, field) is always string.

So, for example, suppose a form has a field num whose type is integer, and in the view we use input_value(form, :num) to get the number and render some preview based on the num, then on a change to num, input_value(form, :num) will return the string representation of an the integer, and so the compiler will complain with invalid argument as the expected integer is now a string.

The same happens with DateTime fields. Is there a known way of casting form fields back to their original types once they’ve been passed through a changeset?

(Apologies for the long-winded question - couldn’t figure out how to frame my problem better)

Yeah I’d love to see how people are doing it too. In my current project I just manually cast them back based on the schema type (not very well tested)

If I understood correctly if you are using Ecto changesets, then the changeset.changes will have the correct field with the right types.

If you are using Repo and Context for the operations then this is all handled for you behind the curtain so you wouldn’t have to deal with it.

If you want to operate on the raw data then use the changeset.changes but make sure they exist before you work on them.

Schema

  schema "stuff" do
    field :number, :integer
    field :date, :naive_datetime
    field :message, :string
  end

Controller

http_params = %{"date" => "2021-01-01". "number" => "23", "message" => "test"}
changeset = Schema.changeset(%Stuff{}, http_params)

IO.inspect(changeset)

would yield to something like:

#Ecto.Changeset<
  action: nil,
  changes: %{message: "test", number: 23},
  errors: [
    date: {"is invalid", [type: :naive_datetime, validation: :cast]}
  ],
  data: #Stuff<>,
  valid?: false
>
1 Like