arcanemachine

arcanemachine

Programming Phoenix LiveView B9.0: "The Promo Live View" section does not work without modification when using Phoenix ~> 1.7.3 and LiveView ~> 0.19.0 (p. 130)

Disclaimer: I hope all of this is accurate, and not the result of some stupid typo I failed to notice. Anyways…

This post comprises 2 issues in the same section “The Promo Live View”. The first issue is relatively minor, but the second issue required some digging to fix:

  1. The PDF e-book contains an image on page 132 that shows a basic promo page in the browser (ie. no form is visible). However, the code sample on the previous page contains a <.simple_form> Live Component which will not properly render until after the code below the aforementioned image has been added. I am guessing the intention was to show the basic rendered page before adding the form component. By adding the code snippet on page 132, the issue is resolved. No big deal. However, another issue arose as I continued…

  2. On page 133, the code snippet presents <.simple_form> component contains an <.input> component that binds the field attribute as follows:

<.input field={{f, :first_name}} type="text" label="First name" />
<.input field={{f, :email}} type="email" label="Email address" phx-debounce="blur" />

However, when using Phoenix ~> 1.7.3 and LiveView ~> 0.19.0, this results in the following error:

key :name not found in: %{
  id: nil,
  label: "First name",
  type: "text",
  prompt: nil,
  field: {%Phoenix.HTML.Form{
     source: #Ecto.Changeset<
       action: nil,
       changes: %{},
       errors: [
         first_name: {"can't be blank", [validation: :required]},
         email: {"can't be blank", [validation: :required]}
       ],
       data: #Pento.Promo.Recipient<>,
       valid?: false
     >,
     impl: Phoenix.HTML.FormData.Ecto.Changeset,
     id: "promo-form",
     name: "recipient",
     data: %Pento.Promo.Recipient{first_name: nil, email: nil},
     hidden: [],
     params: %{},
     errors: [],
     options: [
       method: "post",
       id: "promo-form",
       multipart: false,
       "phx-change": "validate",
       "phx-submit": "save"
     ],
     index: nil,
     action: nil
   }, :first_name},
  errors: [],
  rest: %{},
  multiple: false,
  __changed__: nil,
  __given__: %{
    label: "First name",
    type: "text",
    field: {%Phoenix.HTML.Form{
       source: #Ecto.Changeset<
         action: nil,
         changes: %{},
         errors: [
           first_name: {"can't be blank", [validation: :required]},
           email: {"can't be blank", [validation: :required]}
         ],
         data: #Pento.Promo.Recipient<>,
         valid?: false
       >,
       impl: Phoenix.HTML.FormData.Ecto.Changeset,
       id: "promo-form",
       name: "recipient",
       data: %Pento.Promo.Recipient{first_name: nil, email: nil},
       hidden: [],
       params: %{},
       errors: [],
       options: [
         method: "post",
         id: "promo-form",
         multipart: false,
         "phx-change": "validate",
         "phx-submit": "save"
       ],
       index: nil,
       action: nil
     }, :first_name},
    __changed__: nil
  },
  inner_block: []
}

I made a couple small changes to get things working:

lib/pento_web/live/promo_live.html.heex (Modify the <.input> components)
  <.input field={f[:first_name]} type="text" label="First name" phx-debounce="500" />
  <.input field={f[:email]} type="email" label="Email address" phx-debounce="blur" />

I took inspiration for these changes by copying from the LiveView docs.

However, a different section of the same docs page suggests that the current approach taken by the book is discouraged and that a different approach should be used. I’m looking into this now (and I’m way out of my league… I am not up to snuff on using forms in Phoenix/LV) and will suggest a revised approach if I can 1) figure it out, and 2) get it working with the process described in the book.

Marked As Solved

SophieDeBenedetto

SophieDeBenedetto

Author of Programming Phoenix LiveView

Thanks for your submission! We’re hard at work updating all of the code in the book for the latest release, and the issues you point out here should be addressed by that.

Also Liked

arcanemachine

arcanemachine

OK, I whipped up an implementation based on some of the examples found in the generated code created while I was working on the project. I don’t know if it’s better. All I know is that it works, it matches the style of the generated code (which I assume is reasonably relevant), and it matches the info I found on this LiveView docs page that I referenced in my original post.

lib/pento_web/live/promo_live.ex
defmodule PentoWeb.PromoLive do
  use PentoWeb, :live_view
  alias Pento.Promo
  alias Pento.Promo.Recipient

  @impl true
  def mount(_params, _session, socket) do
    changeset = Promo.change_recipient(%Recipient{})

    {:ok, socket |> assign_form(changeset)}
  end

  defp assign_form(socket, %Ecto.Changeset{} = changeset) do
    assign(socket, :form, to_form(changeset))
  end

  @impl true
  def handle_event("validate", %{"recipient" => recipient_params}, socket) do
    changeset = %Recipient{}
      |> Promo.change_recipient(recipient_params)
      |> Map.put(:action, :validate)

    {:noreply, assign_form(socket, changeset)}
  end

  def handle_event("save", %{"recipient" => recipient_params}, socket) do
    changeset = %Recipient{}
      |> Promo.change_recipient(recipient_params)

    if changeset.valid? do
      {:noreply, socket |> put_flash(:info, "Form submitted successfully.")}
    else
      {:noreply,
       socket
       |> put_flash(:error, "Please fill out the form correctly before continuing.")}
    end
  end
end
lib/pento_web/live/promo_live.html.heex
<.header>
  Send Your Promo Code to a Friend
  <:subtitle>promo code for 10% off their first game purchase!</:subtitle>
</.header>

<.simple_form
  for={@form}
  id="promo-form"
  phx-change="validate"
  phx-submit="save"
>
  <.input field={@form[:first_name]} type="text" label="First name" />
  <.input field={@form[:email]} type="email" label="Email address" phx-debounce="blur" />

  <:actions>
    <.button phx-disable-with="Sending...">Send Promo</.button>
  </:actions>
</.simple_form>
lurnid

lurnid

I’m going through B10.0 and agree with point 1 of the OP. The B10.0 book, at the end of p 137 says:

Start up the server, log in, and point your browser at /promo. You should see the following:

But trying to view the /promo path at this point will throw an error because the code that follows on pp 138 is needed for the page to load successfully.

It would be better to not ask the reader to load the /promo path until after the code on pp 138 otherwise (as I did) the will end up thinking that the error was due to a mistake in the code they wrote rather than the fact that the code isn’t complete for rendering the view.

mostalive

mostalive

For me the problem here was that the code for the <.simple_form appeared too early (page 136 and 137 in PDF B10.0 ). It is explained, and re-appears later on page 139.
Without <simple_form the live view worked, and seeing the page gave me a sense of progress. Adding the form on page 139, once the wiring was there, was smooth.

Where Next?

Popular Pragmatic Bookshelf topics Top

abtin
page 20: … protoc command… I had to additionally run the following go get commands in order to be able to compile protobuf code using go...
New
Mmm
Hi, build fails on: bracket-lib = “~0.8.1” when running on Mac Mini M1 Rust version 1.5.0: Compiling winit v0.22.2 error[E0308]: mi...
New
Chrichton
Dear Sophie. I tried to do the “Authorization” exercise and have two questions: When trying to plug in an email-service, I found the ...
New
fynn
This is as much a suggestion as a question, as a note for others. Locally the SGP30 wasn’t available, so I ordered a SGP40. On page 53, ...
New
jgchristopher
“The ProductLive.Index template calls a helper function, live_component/3, that in turn calls on the modal component. ” Excerpt From: Br...
New
brunogirin
When trying to run tox in parallel as explained on page 151, I got the following error: tox: error: argument -p/–parallel: expected one...
New
mert
AWDWR 7, page 152, page 153: Hello everyone, I’m a little bit lost on the hotwire part. I didn’t fully understand it. On page 152 @rub...
New
andreheijstek
After running /bin/setup, the first error was: The foreman' command exists in these Ruby versions: That was easy to fix: gem install fore...
New
a.zampa
@mfazio23 I’m following the indications of the book and arriver ad chapter 10, but the app cannot be compiled due to an error in the Bas...
New
SlowburnAZ
Getting an error when installing the dependencies at the start of this chapter: could not compile dependency :exla, "mix compile" failed...
New

Other popular topics Top

PragmaticBookshelf
Stop developing web apps with yesterday’s tools. Today, developers are increasingly adopting Clojure as a web-development platform. See f...
New
PragmaticBookshelf
Brace yourself for a fun challenge: build a photorealistic 3D renderer from scratch! In just a couple of weeks, build a ray tracer that r...
New
AstonJ
You might be thinking we should just ask who’s not using VSCode :joy: however there are some new additions in the space that might give V...
New
Rainer
My first contact with Erlang was about 2 years ago when I used RabbitMQ, which is written in Erlang, for my job. This made me curious and...
New
AstonJ
poll poll Be sure to check out @Dusty’s article posted here: An Introduction to Alternative Keyboard Layouts It’s one of the best write-...
New
AstonJ
In case anyone else is wondering why Ruby 3 doesn’t show when you do asdf list-all ruby :man_facepalming: do this first: asdf plugin-upd...
New
PragmaticBookshelf
Create efficient, elegant software tests in pytest, Python's most powerful testing framework. Brian Okken @brianokken Edited by Kat...
New
rustkas
Intensively researching Erlang books and additional resources on it, I have found that the topic of using Regular Expressions is either c...
New
AstonJ
If you get Can't find emacs in your PATH when trying to install Doom Emacs on your Mac you… just… need to install Emacs first! :lol: bre...
New
AstonJ
This is a very quick guide, you just need to: Download LM Studio: https://lmstudio.ai/ Click on search Type DeepSeek, then select the o...
New

Sub Categories: