Why is there !!@current_scope on line 33 of the generated code? What is this accomplishing?
Why is there a :let={f} on line 26? I see that is accessed on line 34, but I don’t understand why we can’t just use @form here and avoid the let?
For context here is are lines 25-44 of the generated login page:
<.form
:let={f} #why the let binding?
for={@form}
id="login_form_magic"
action={~p"/users/log-in"}
phx-submit="submit_magic"
>
<.input
readonly={!!@current_scope} #why the double negation?
field={f[:email]}
type="email"
label="Email"
autocomplete="username"
required
phx-mounted={JS.focus()}
/>
<.button class="w-full" variant="primary">
Log in with email <span aria-hidden="true">→</span>
</.button>
</.form>
This pattern is repeated for the second form for logging in with email and password. I’ve searched through the Phoenix documentation and I haven’t found anything helpful. I’ll admit I don’t grok the :letspecial attribute 100% so maybe that is the source of my confusion.
Probably to handle nil values so when @current_scope is not explicitly set, the readonly attribute gets set to false.
I think it’s so that the login form submission can degrade gracefully by falling back to a regular HTTP request via the url specified by the action attribute.
The login is always submitted via POST, the LiveView is just used for validation.
I don’t think that has anything to do with the :let though (unless there’s something I’m unaware of). It was changed from the @form[] syntax in this PR by @steffend - it’s a large diff with a lot going on, so it’s possible it just got left in as an oversight. Or perhaps it does something I’m not aware of
The docs discourage the use of :let on forms because it disables the fancy field change-tracking they added in LV1.0.
The :let is there because otherwise the inputs would have duplicate IDs, as we render the form twice. Another solution would be to assign two separate forms that already have an ID set.
My mind was in Elixir land where, in most cases, transforming nil into false wouldn’t matter, but this makes sense for an HTML attribute.
Thanks for the insight. I can say that the two form solution would be easier for me to read, but I’m glad to have learned something about reusing forms.
The form is submitted to the LiveView first for validation. If it passes validation, the LiveView uses phx-trigger-action to submit the form via POST to the session controller.
The form has to go through a POST because LiveView can’t set the session cookie. Only an HTTP request can set an HttpOnly cookie (the cookie is HttpOnly for security reasons).