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

johnp
Running the examples in chapter 5 c under pytest 5.4.1 causes an AttributeError: ‘module’ object has no attribute ‘config’. In particula...
New
raul
Hi Travis! Thank you for the cool book! :slight_smile: I made a list of issues and thought I could post them chapter by chapter. I’m rev...
New
leonW
I ran this command after installing the sample application: $ cards add do something --owner Brian And got a file not found error: Fil...
New
patoncrispy
I’m new to Rust and am using this book to learn more as well as to feed my interest in game dev. I’ve just finished the flappy dragon exa...
New
jskubick
I think I might have found a problem involving SwitchCompat, thumbTint, and trackTint. As entered, the SwitchCompat changes color to hol...
New
nicoatridge
Hi, I have just acquired Michael Fazio’s “Kotlin and Android Development” to learn about game programming for Android. I have a game in p...
New
s2k
Hi all, currently I wonder how the Tailwind colours work (or don’t work). For example, in app/views/layouts/application.html.erb I have...
New
Henrai
Hi, I’m working on the Chapter 8 of the book. After I add add the point_offset, I’m still able to see acne: In the image above, I re...
New
New
ggerico
I got this error when executing the plot files on macOS Ventura 13.0.1 with Python 3.10.8 and matplotlib 3.6.1: programming_ML/code/03_...
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
dasdom
No chair. I have a standing desk. This post was split into a dedicated thread from our thread about chairs :slight_smile:
New
DevotionGeo
I know that -t flag is used along with -i flag for getting an interactive shell. But I cannot digest what the man page for docker run com...
New
New
AstonJ
Curious to know which languages and frameworks you’re all thinking about learning next :upside_down_face: Perhaps if there’s enough peop...
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
Biggest jackpot ever apparently! :upside_down_face: I don’t (usually) gamble/play the lottery, but working on a program to predict the...
New
Maartz
Hi folks, I don’t know if I saw this here but, here’s a new programming language, called Roc Reminds me a bit of Elm and thus Haskell. ...
New
PragmaticBookshelf
Author Spotlight Rebecca Skinner @RebeccaSkinner Welcome to our latest author spotlight, where we sit down with Rebecca Skinner, auth...
New
PragmaticBookshelf
Explore the power of Ash Framework by modeling and building the domain for a real-world web application. Rebecca Le @sevenseacat and ...
New

Sub Categories: