kartheek

kartheek

Indy Forms - Simplify Your Forms

Indy Forms

Forms can be simplified using IndyForm. A form can be implemented in just couple of lines.

  use IndyForm.FormComponent, context: Context

  form_component(form_key, create_action, update_action, opts)
  • form_key: is your schema name. This is used for finding the form in the params.
  • create_action: can be an atom or list of atoms. This is used to determine what action should be performed - create or update.
  • update_action: can be an atom or list of atoms. This is used to determine what action should be performed - create or update.
    create_action or update_action values can be directly mapped to socket.assigns.live_action values.
  • opts: change_listeners can be enabled through opts
  form_component(form_key, create_action, update_action, change_listeners: true)

Example

A complete example which reduces around 50 lines of boilerplate code form component to 3 just lines:

defmodule UserForm do
  alias IndyFormSample.Accounts, as: Context

  use IndyForm.FormComponent, context: Context

  form_component("user", :new, :edit)
end

or can be writen in verbose 7 lines if you prefer this way:

defmodule UserForm do
  alias IndyFormSample.Accounts, as: Context

  use IndyForm.FormComponent, context: Context

  @form_key "user"
  @create_action :new
  @edit_action :edit

  form_component(@form_key, @create_action, @edit_action)
end

Value Change Listeners

on_value_change/2 is invoked when there is a change is detected in field while handling validate event.

key is an atom - which is field name defined in your form.

You can override to handle changes in form happening without writing a single line of javascript.

Note: Don’t forget to enable value change listeners by passing change_listeners: true through form_component opts.

  # handle changes relating to field :contact_me
  def on_value_change(socket, {:contact_me, _old_value, new_value}) do
    show_phone? = show_phone?(new_value)
    show_email? = show_email?(new_value)

    socket
    |> assign(:show_phone, show_phone?)
    |> assign(:show_email, show_email?)
  end

  # needed for handling changes not relating to our fields of interest
  def on_value_change(socket, _), do: socket

Design Goals

Design goals of this library :

  • less code injection through macros.
  • less magic and more explicit configuration.
  • flexibility to override everything to perform one off customizations.
  • reduce boilerplate code in application.

You can read docs about forms and contexts.

Browse code at GitHub - lkarthee/indy_form: Simplify LiveView Forms.

And browse sample code here - GitHub - lkarthee/indy_form_sample: A sample project using IndyForm

I want hear more from you - please share feedback or discuss about use cases or suggest design changes.

Note: this library is not published on Hex. You can use it from GitHub. I want to publish after hearing your feedback.

Regards
Kartheek

Edits: changed sample code to reflect few changes.

Most Liked

al2o3cr

al2o3cr

One consistent pain-point with libraries like this (not Elixir-specific, see also Devise and many others) is providing enough hooks / APIs / abstraction-points that people can customize the behavior without having to start over from scratch.

For instance, what if I wanted to display a different flash message when creation succeeds? The current messages are hard-coded deep inside apply_crud_action:

I18n could be an easy-to-add escape hatch for this particular case, since it’s just text.

But things get rougher for behavioral changes: for instance, if I wanted to display a “your changes couldn’t be saved” flash message on error. That’s also buried inside of create and update, and not easily overridable.

derpycoder

derpycoder

Phoenix 1.7 is going to have redesigned Form API, because form API sucks.

Chris McCord iterated at the end of his ElixirConf 2022 talk.
How can your library help with that kind of problem?

For instance, he mentions choose your own adventure kind of form, i.e. based on your previous selection, new form sections get rendered. (Which doesn’t work well with Ecto Changesets and Phoenix HTML Form data protocol.)

kartheek

kartheek

Thank you @al2o3cr for your feedback.

I have refactored library:

  • to include on_event, on_error to handle more scenarios.
  • removed name param to the macro from which flash messages were being generated.

Please look at this version and provide your inputs if any.

It does not make sense to generate flash messages - considering issues relating to i18n and message customisation. on_error/2 and on_success/2 can be overridden to generate flash messages.

It’s a challenge to keep up with changes in Phoenix Live View with every release and its not abnormal considering it has not yet reached 1.x .

With a fairly large application with more than 50 form components - i ended up with a lot of files and heex templates. When migrating from controller based pages to live view I faced a lot of issues with boilerplate code. In mid way, I stopped the migration and refactored all the migrated live view pages using high level components.

I realised that the only way to stabilise my application code is by using stable things from Live View and fill pages with high level components. That way if I have to upgrade to a new release of LiveView, i will just upgrade the high level components like form, table, etc. Even the .heex pages are filled with either html tags or high level components. I got rid of <%= if … do %> tags with 0.18.x.

derpycoder

derpycoder

This link is broken.

kartheek

kartheek

Fixed it thanks.

Where Next?

Popular in Libraries Top

mhanberg
I just released the first version of Temple: an HTML DSL for Elixir and Phoenix! You can read this blog post or the docs for more info...
New
tmbb
I’ve been working on two packages (not on hex.pm yet) to build admin interfaces for phoenix apps: bureaucrat - which contains a bunch ...
New
woylie
I released Doggo, a collection of unstyled Phoenix components. Features Unstyled Phoenix components. Storybook that can be added to...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 49522 488
New
OvermindDL1
Been making an MLElixir thing (not released yet…) for fun in spare time in the past day. I’m just trying to see how much I can get an ML...
132 13487 106
New
danschultzer
In short Plug n’ play OAuth 2.0 provider library. Just set up a resource owner schema with Ecto (your user schema), install the dependen...
New
benlime
LiveMotion enables high performance animations declared on the server and run on the client. As a follow up to my previous thread A libr...
New
Crowdhailer
Experimenting with this code. OK.try do user &lt;- fetch_user(1) cart &lt;- fetch_cart(1) order = checkout(cart, user) save_or...
New
OvermindDL1
I created a new library (rather I pulled out a couple files from my big project), it manages an operating system PID file for the BEAM. ...
New
bluzky
You may know https://ui.shadcn.com/, a UI component library for React. I really love it’s design style and components. I’ve built some co...
381 12391 119
New

Other popular topics Top

sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
977 41022 311
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
Nvim
Elixir appears to be a superior language to Python. I don’t see any advantage of Python over Elixir. Are there any?
New

Sub Categories:

We're in Beta

About us Mission Statement