kartheek

kartheek

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 · GitHub.

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

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.

Showing Posts 1 to 7

derpycoder

derpycoder

kartheek

kartheek OP

Fixed it thanks.

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.)

derpycoder

derpycoder

I see some ways to solve that issue in your example code: Awesome!!

def on_init(socket) do
  show_phone? = show_phone?(socket.assigns.row.contact_me)
  show_email? = show_email?(socket.assigns.row.contact_me)
  socket
  |> assign(:show_phone, show_phone?)
  |> assign(:show_email, show_email?)
end

defp show_phone?(value) do
  value in [:phone, :phone_email]
end

defp show_email?(value) do
  value in [:email, :phone_email]
end
<%= if @show_phone do %>
  <%= label f, :phone %>
  <%= text_input f, :phone %>
  <%= error_tag f, :phone %>
<% end %>

<%= if @show_email do %>
  <%= label f, :email %>
  <%= text_input f, :email %>
  <%= error_tag f, :email %>
<% end %>
kartheek

kartheek OP

I am looking forward for 1.7 release and all the exciting things.

Not a replacement for Phoenix forms or LiveView Form rather builds over on top of them.

It is more of high level library which abstract things over UI patterns like forms with master row and child line items, show delete popups, refresh dependent fields, etc

It does three things:

  • Reduce boilerplate code when writing form components.
  • Server side Value change listeners - no need to write javascript for that
  • Handles navigation after creating or updating row.

In applications where there are a lot of forms - it will simplify many things.

My forms look like this after using this library:

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:

https://github.com/lkarthee/indy_form/blob/main/lib/form_component.ex#L121-L133

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.

kartheek

kartheek OP

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.

— All posts loaded —

Where Next? Top

Trending in Announcing Top

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...
387 15136 120
New
woylie
Flop is an Elixir library that applies filtering, ordering and pagination parameters to your Ecto queries. offset-based pagination with...
New
restlessronin
The repo is at GitHub - cyberchitta/openai_ex: Community maintained Elixir library for OpenAI API · GitHub. Docs are at OpenaiEx User Gu...
152 11030 135
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
shahryarjb
The Chelekom project is a library of Phoenix and LiveView components generated via Mix tasks to fit developer needs seamlessly. One of i...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
woylie
Phoenix components for pagination, sortable tables and filter forms with Flop and (optionally) Ecto. pagination cursor pagination sorta...
New

Other Trending Topics Top

mudasobwa
I am seeing a lot of aplications of Argumentum ad Vericundiam in software discussions. They do link some piece of writing and point us to...
New
bartblast
Hey folks, I just published a post about Hologram’s funding and where the project goes next - the short version: Curiosum as Main Spons...
New
alexslade
Fly’s CEO posted this recently - Turn And Face The Strange · The Fly Blog It says that Fly is going all-in on sprites, which is a worry ...
New
Herve37
We’re evaluating API mocking tools for OpenAPI-based projects and would love to hear what other teams are using. We’re particularly inte...
New
sorenone
Today we’re releasing Oban for Python. Not an Oban client in Python. Not a pythonx wrapper embedded in Elixir. Nope, it’s a fully operati...
New
lawik
I was thinking since Goatmire Elixir turned out pretty good I should maybe do another one. 30th of Sep - 2nd of Oct this year./ The firs...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews