hubertlepicki

hubertlepicki

Spike - a library that helps you build stateul, server-memory backed forms in Elixir (LiveView / Surface UI)

I have published a library, extracted from one of the closed-source apps, that may help you build complex form without the use of Ecto/changesets.

The library came to existence from the difficulty of creating big, often deeply nested forms, where validations of form fields depend on values of other fields, including fields in children, parent or sibling changesets.

The library consists of 3 parts:
Spike - core library, allows for form creation and manipulation
Spike.LiveView - LiveView bindings
Spike.Surface - Surface UI bindings

A good starting point, if you’re interested how it works, is having a look at my example application, which provides direct links to sources and documentation for each of the individual libraries.

Feedback very much welcome.

Most Liked

hubertlepicki

hubertlepicki

Good question, and not one I was contemplating conciously. I don’t know if it fits my use case. I don’t want to submit whole forms, the idea is to submit individual fields. So, as it is now, each input sends spike-form-event:set-value to the backend, which updates only one form field. The form, as a whole, lives on the server, on the client it’s just a bunch of individual inputs.

I wasn’t making a conscious decision not to use Phoenix.HTML.Form but there are several factors why I figured focusing on individual fields rather than one HTML element

  1. I can spread the inputs / controls throughout the page, not worrying about nesting HTML form tags or even validity of HTML, mixing parent, children and even unrelated forms together

  2. Some of my “forms” are not really forms at all, but “backend structures for the UI” with input element here and there

  3. Changing / submitting the form doesn’t require the whole form to be submitted. Only changed field is submitted to the backend. I guess this could even be improved by just sending diff. I need to look into that as we do indeed have some long text inputs that could use an improvement. But sending one of them, rather than 3, is already an improvement. We don’t yet do that, but we’re looking into collaboration of multiple users on the same form, I think syncing individual inputs rather than whole edits of whole forms is going to be easier.

With 3) there is a possible issue of race condition where some input wasn’t synced yet and user hits “Save”, but I am working this around for now with a slight delay on the “Submit” button and users haven’t reported problems. Something to consider.

LostKobrakai

LostKobrakai

I’d be curious why you didn’t implement Phoenix.HTML.Form to be able to use the existing phoenix helpers to build the markup, just powered by a different system beneight.

Eiji

Eiji

The Spike readme file does not have defined elixir as a code language after ```, so on github it does not have syntax highlight.

How about making 2nd argument of Spike.append/4 and Spike.update/3 optional?

For example Instead of:

  @doc false
  def append(%{ref: ref} = struct, ref, field, params) do
    append(struct, field, params)
  end

  @doc false
  def append(struct, ref, field, params) do
    append_embeds(struct, ref, field, params, embeds(struct))
  end

You could have:

  @doc false
  def append(struct, ref \\ nil, field, params)
  def append(struct, nil, field, params) do
    append(struct, field, params)
  end

  @doc false
  def append(struct, ref, field, params) do
    append_embeds(struct, ref, field, params, embeds(struct))
  end

Do you plan any support for i18n error messages? Just returning %{field_name: "spike.validations.acceptance"} as a result of an extra function would help a lot I think. Also equivalent of Ecto.Changeset.validations/1 would be amazing.

Do you plan to support custom types (like Ecto.Type), so developers does not need to validates multiple times?

Do you have plans for optional ecto support in future creating for example by spike_ecto?

egze

egze

That looks super nice. I’m curious how you would build a form, where the structure is provided at runtime. My common use-case lately is receiving a JSON-Schema and rendering a form dynamically.

Similar to this: GitHub - json-editor/json-editor: JSON Schema Based Editor

hubertlepicki

hubertlepicki

Answering your questions,

  1. Spike.append/update default param is great idea, opened an issue and is now on my todo list.
    Make 2nd argument for Spike.update and Spike.append optional · Issue #6 · hubertlepicki/spike · GitHub

  2. I18n great idea, opened issue
    Support gettext for error messages · Issue #2 · hubertlepicki/spike · GitHub

  3. The casting & validations are something I need to rethink. This has been put together very quickly to make it work, and uses Vex and Tarams libraries. Tarams already steals code from Ecto, I believe, so you can define own types. But I do need to rethink both of these decisions in long term.

  4. spike_ecto no, the way I use these forms are entirely in-memory and then, after form is “valid” I feed the valid form to a workflow that performs some actions. Doing ecto inserts / updates / removes manually does not bind the database schema to UI, which I think is an antipattern :slight_smile:

I suspect my main focus shortly will be the performance improvements Improve performance of very large forms · Issue #1 · hubertlepicki/spike · GitHub It’s not a big problem in the app I use it in, as the “large” forms maybe have dozens of child records but there is no good reason it shouldn’t support thousand or more child forms. Currently the updates are doing very naive walkthrough of the graph and this can be and should be improved.

Where Next?

Popular in Libraries Top

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
achempion
Hi, I would like to tell about my initiative to further maintain and develop Waffle project which is the fork of Arc library. The progre...
New
mplatts
With HEEX released we decided to start a components library using Tailwind CSS - check it out here: Petal Components. We also have a boi...
New
mcrumm
If you would like to migrate away from node/npm/webpack while still using sass, the dart_sass package provides a installer and runner for...
New
asiniy
Hey there! I wrote a download elixir package which does exactly what its name about - an easy way to download files. I saw solutions ...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 35421 110
New
jakub-zawislak
Hi everyone, I’m coming from the Symfony (PHP) framework. I like Phoenix, but it has a one thing that was build much better in the Symfo...
New
Crowdhailer
I have been updating a library that allows you to pipe between functions that use the erlang result tuple convention. Assuming you have...
New
bryanjos
Hi, I wanted share a small library we at Revelry Labs made for rendering react components from the server side. There are instructions fo...
New

Other popular topics Top

freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
William
I would like to know that is there any online source for learning Phoenix Framework for building E-Commerce Store? Any advantage on build...
New
AstonJ
You’re a programmer, so you don’t need spoon feeding with the conventional drivel about “this is an integer.” No. You need to know what’s...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? https://hexdocs.pm/ecto/Ecto.Repo.h...
New
beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> someth...
New

Sub Categories:

We're in Beta

About us Mission Statement