clemensm
How to use live_view as a standin for CRUD forms, falling back to default controller behaviour if JS is disabled
Hello everyone
I’ve recently started digging into phoenix LiveView, and so far I really like what I am seeing. Currently I am trying to enhanve a simple CRUD form with LiveView to get live validation, but so that this is optional and the site will still work if JavaScript has been disabled. From what I understand that’s one of the use cases for using LiveView, so here’s my problem:
The LiveView is being called from inside my phoenix controller using live_render, like so:
defmodule SomeController do
def new(conn, _params) do
live_render(conn, SomeLiveView)
end
end
and the SomeLiveView can easily create an empty changeset and pass that to the .leex template:
defmodule SomeLiveView do
...
def mount(_param, _session, socket) do
changeset = SomeSchema.new_changeset()
{:ok, assign(socket, changeset: changeset, endpoint: socket.endpoint)}
end
end
<%= form_for @changeset, Routes.some_path(@endpoint, :create), [phx_change: :validate], fn f -> %>
...
<% end %>
And everything works fine, and on submit (also with JS disabled) the usual :create path is called in the SomeController.
Howerver this is where I’ve got my problem: The :create method in the SomeController will validate the form again, and it’s possible that for some reason it cannot be saved. Usually we’d simply render the form again with the changeset and the errors, however I do not understand how this can be done. The naive version of simply passing the changeset as a param does not seem to work, because the LiveView is not connected to the router directly:
defmodule SomeController do
def create(conn, %{"some" => params}) do
case SomeSchema.create(params) do
...
{:error, %Ecto.Changeset{} = changeset} ->
live_render(conn, SomeLiveView, params: %{changeset: changeset})
end
end
If I do this, the param argument of mount is only :not_mounted_at_router. Of course I could try to pass the changeset in the session instead, however the documentation is very clear that this is not a good idea as that data would be serialised and sent to the client.
I also now about the user demo app, but there they create a LiveView for each path (which seems quite a lot of duplication to me), and they have no option to fallback to standard phoenix controllers if JS is disabled.
So my question is: Has anybody else solved this problem already, or knows what the solution looks like?
Thanks
Clemens
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #hex
- #performance










First 10 of 11 Posts
andreaseriksson
Honestly, why do you make it this complicated? If the user has JS disabled, basically every web page would be broken. This is considered an extrem edgecase IMO.
pedromvieira
I had the same thought. Is it even possible to run Phoenix basic form without JS? (Ok, It can be created manually with “pure” html)
jonathanpglick
I applaud your effort to make this work both with and without JS. People seem to forget that forms can really do a lot on their own. And it’s a great exercise for accessibility and other issues like low-bandwidth or spotty connections.
I’m curious to see what you come up with since I’ve wanted to use LiveView for a similar “up-casting” of basic forms!
clemensm
Well, turning off JS is probably the most efficient way to stop everyone tracking you across the web.
And I don’t see why my pages should be broken for people who decide that JS on by default is a bad choice, just because everyone else thinks it’s fine that a blog with only static content should be a completely blank page if I turn of JS.
crova
I strongly agree with both previous posts.
Lately I’ve been looking for a similar idea with cookies and content depended on them.
If you find a conclusive solution for you problem I would love to hear about it.
andreaseriksson
Sure, but why do you need LiveView for static content?
andreaseriksson
However reading you question in the first post again, I would consider mounting the LiveView in the templates instead of the controller and only use it for the UX that you need (live validation?)
LostKobrakai
Instead of sending the changeset to the liveview you could send the submitted params and create the changeset within the liveview again. But do you really expect a form, which was submitted because of no JS to suddenly have JS? I personally would just stick to a non liveview version until the submission was successful.
clemensm
So after reading through the replies I believe that I’ve come up with a workable solution that can be used as a standin, but it does require a bunch of changes in different places, so let’s start with an overview of what need’s to be done:
:editand:newpaths, and replace them withlive_path’s.:editand:newfunctions, we no longer need them. Also delete thenew.html.eexandedit.html.eextemplates, this will be handled by the LiveView in the future.I.e. if we take the example from my question, we need all these (I’ve left out the validation step, as that is rather trivial to add):
Sorry for the rather long post, but so far this seems like the cleanest solution to me. Tested this with JS active/deactivated in the browser, and is working fine for me. The only thing left to do is to wrap all the boilerplate stuff about reply etc in the Helper into a macro so that we can simply write that stuff and only provide the functions for validation/creation/updates.
sntran
I also like to see that we have a better way of handling this use case. Not everybody will have JS enabled, so we should always try to make a web page accessible without JS first, then enhance it with JS.
This way, your web page will always work. It just works “nicer” when JS is enabled.
Form is a strong example. Form has been working fine without JS. People just forget how we did thing before.