Phoenix forms without changesets!
Notes
Typically, we back Phoenix forms with an Ecto changeset
.
But sometimes, I prefer having more of a separation between the form, which is part of my UI, and the changeset that stores data in the database.
If we use the same changeset, it feels like our UI knows too much about our persistence logic.
One way to split that is to use Phoenix’s new to_form/2
helper (and
protocol).
The protocol is already implemented for changesets, so you can continue using the changeset in a form. For example, it might look something like this:
changeset = Blog.new_post()
assign(socket, form: to_form(changeset))
But the to_form/2
protocol is also implemented for regular maps. So, we can
back our forms with a simple map!
fields = %{"title" => "", "body" => ""}
assign(socket, form: to_form(fields))
Handling errors
But one of the cool things about the changeset integration with Phoenix forms is how they automatically handle errors.
Thankfully, the to_form/2
helper has a nice way of dealing with errors.
It takes a set of options, one of which is an errors
key. If we pass a map of
errors (field name to error), then it’ll work exactly like changesets work! 🥳
So, we could do something like this:
fields = %{"title" => "", "body" => ""}
errors = [title: "Can't be blank"]
assign(socket, form: to_form(fields, error: errors))
That’s hardcoded, but you can get those errors from your domain modules (and in
the video, it’s actually the value returned by changeset.errors
).
Pretty cool, right?