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
belgoros
Following the steps described in Chapter 6 of the book, I’m stuck with running the migration as described on page 84: bundle exec sequel...
New
brianokken
Many tasks_proj/tests directories exist in chapters 2, 3, 5 that have tests that use the custom markers smoke and get, which are not decl...
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
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
alanq
This isn’t directly about the book contents so maybe not the right forum…but in some of the code apps (e.g. turbo/06) it sends a TURBO_ST...
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
akraut
The markup used to display the uploaded image results in a Phoenix.LiveView.HTMLTokenizer.ParseError error. lib/pento_web/live/product_l...
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
dtonhofer
@parrt In the context of Chapter 4.3, the grammar Java.g4, meant to parse Java 6 compilation units, no longer passes ANTLR (currently 4....
New

Other popular topics Top

Devtalk
Hello Devtalk World! Please let us know a little about who you are and where you’re from :nerd_face:
New
Exadra37
I am thinking in building or buy a desktop computer for programing, both professionally and on my free time, and my choice of OS is Linux...
New
AstonJ
I have seen the keycaps I want - they are due for a group-buy this week but won’t be delivered until October next year!!! :rofl: The Ser...
New
AstonJ
Do the test and post your score :nerd_face: :keyboard: If possible, please add info such as the keyboard you’re using, the layout (Qw...
New
Exadra37
Oh just spent so much time on this to discover now that RancherOS is in end of life but Rancher is refusing to mark the Github repo as su...
New
PragmaticBookshelf
Author Spotlight Jamis Buck @jamis This month, we have the pleasure of spotlighting author Jamis Buck, who has written Mazes for Prog...
New
Help
I am trying to crate a game for the Nintendo switch, I wanted to use Java as I am comfortable with that programming language. Can you use...
New
AstonJ
If you want a quick and easy way to block any website on your Mac using Little Snitch simply… File &gt; New Rule: And select Deny, O...
New
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: