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
jimmykiang
This test is broken right out of the box… — FAIL: TestAgent (7.82s) agent_test.go:77: Error Trace: agent_test.go:77 agent_test.go:...
New
GilWright
Working through the steps (checking that the Info,plist matches exactly), run the demo game and what appears is grey but does not fill th...
New
jesse050717
Title: Web Development with Clojure, Third Edition, pg 116 Hi - I just started chapter 5 and I am stuck on page 116 while trying to star...
New
herminiotorres
Hi! I know not the intentions behind this narrative when called, on page XI: mount() |&gt; handle_event() |&gt; render() but the correc...
New
conradwt
First, the code resources: Page 237: rumbl_umbrella/apps/rumbl/mix.exs Note: That this file is missing. Page 238: rumbl_umbrella/app...
New
jeremyhuiskamp
Title: Web Development with Clojure, Third Edition, vB17.0 (p9) The create table guestbook syntax suggested doesn’t seem to be accepted ...
New
creminology
Skimming ahead, much of the following is explained in Chapter 3, but new readers (like me!) will hit a roadblock in Chapter 2 with their ...
New
EdBorn
Title: Agile Web Development with Rails 7: (page 70) I am running windows 11 pro with rails 7.0.3 and ruby 3.1.2p20 (2022-04-12 revision...
New
gorkaio
root_layout: {PentoWeb.LayoutView, :root}, This results in the following following error: no “root” html template defined for PentoWeb...
New

Other popular topics Top

AstonJ
What chair do you have while working… and why? Is there a ‘best’ type of chair or working position for developers?
New
dimitarvp
Small essay with thoughts on macOS vs. Linux: I know @Exadra37 is just waiting around the corner to scream at me “I TOLD YOU SO!!!” but I...
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
DevotionGeo
The V Programming Language Simple language for building maintainable programs V is already mentioned couple of times in the forum, but I...
New
AstonJ
Continuing the discussion from Thinking about learning Crystal, let’s discuss - I was wondering which languages don’t GC - maybe we can c...
New
New
New
CommunityNews
A Brief Review of the Minisforum V3 AMD Tablet. Update: I have created an awesome-minisforum-v3 GitHub repository to list information fo...
New
RobertRichards
Hair Salon Games for Girls Fun Girls Hair Saloon game is mainly developed for kids. This game allows users to select virtual avatars to ...
New
Fl4m3Ph03n1x
Background Lately I am in a quest to find a good quality TTS ai generation tool to run locally in order to create audio for some videos I...
New

Sub Categories: