-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support phx-trigger-action #135
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for taking a stab at this. I'm not sold on the implementation. I think it would work, but I'd like to see if we can find a better design so that it's not intertwined with the maybe_redirect
logic.
What do you think? Could you explore that?
@@ -330,7 +330,22 @@ defmodule PhoenixTest.Live do | |||
end | |||
|
|||
defp maybe_redirect(html, session) when is_binary(html) do | |||
maybe_put_patch_path(session) | |||
case Form.find(html, "form[phx-trigger-action]") do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find it a little strange that we'd be looking for a form inside maybe_redirect
.
I imagine it'd be more duplication to do this in the places where we're submitting forms, but I wonder if we could find a better design for this?
I'd image there are places where we're dealing with a form (probably through a phx-change) where we already have the form
data structure. Maybe we could check for a Form.phx_trigger_action?
there? (similar to how we do it with other attributes like that)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I think the phx-trigger-action
is a bit like a client side redirect.
Two things to consider:
phx-trigger-action
can be set on any re-render, not just when clicking a submit button for a formphx-trigger-action
can be set on any form, not necessarily the one the user is interacting with
I agree that the common use case is:
- User submits form
handle_event("save"
assignstrigger_submit: true
- Browser performs HTTP POST
But I think we should limit the implementation to that common use case.
I think its best to mimmick LiveView JS to support all kinds of uses cases:
Whenever something changed, check the HTML for forms with phx-trigger-action
.
If present, then submit that form.
That's what I tried to to in this PR.
We could separate maybe_redirect
and maybe_trigger_action
.
Do you think that would help?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commit e2dd5b4
I separated them into two separate post processing steps.
I tried to keep both functions completely separate by introducing a token flow.
Feels over-engineered. Maybe just renaming maybe_redirect
to maybe_trigger_form_action_or_redirect
would be good enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels over-engineered. Maybe just renaming maybe_redirect to maybe_trigger_form_action_or_redirect would be good enough?
Yeah, I agree. I appreciate you taking the time to try a different approach to see if we landed at something better. But it does seem to introduce more confusion. I think your original maybe_redirect
implementation was best -- especially since you explained how trigger_action
works. I thought it was more limited.
I think its best to mimmick LiveView JS to support all kinds of uses cases:
I think that's a good north star for sure. As we evaluate what to include and not include, I think there are two levels that I like to keep in mind:
- PhoenixTest not lie to users -- so, tests shouldn't pass if production is going to break.
- It's less bad for tests to break when production would pass (e.g. maybe we don't have a complete implementation). Ideally, we can match production, but I think this should always be secondary to (1).
All that being said, any chance to revert the last commit, and I think we might be good to go? Do you think it'd be helpful to write test cases for the scenarios you mentioned? (when a different event happens and the trigger-action still happens?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reverted and added tests.
Also stumbled over #143.
ac746b2
to
3fd258d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks again for doing this!
I have a few comments and questions that I hope are helpful. Let me know if anything is unclear. I can also try to help out with implementation more, but it seems like you're more up to speed with how phx-trigger-action
works in LiveView.
|
||
session.conn | ||
|> PhoenixTest.Static.build() | ||
|> PhoenixTest.Static.submit_form(form.selector, form_data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a question here. Do you know what happens in a normal LiveView if a form has something like a phx-change
that redirects you somewhere and it has a phx-trigger-action
? Which redirect "wins out"?
In this case, we're giving "priority" to the phx-trigger-action
, which I imagine is the right call since most times I'd expect phx-change
not to be doing the redirecting. But I'm curious if we know what happens in those scenarios (and if we should even concern ourselves with them, or if it's just an edge case that we shouldn't cover).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you maybe have misread the code. Or I'm wrong. Either way, I'm adding a test to clarify.
My understanding:
This implementation already prioritizes redirects or patches.
phx-trigger-action
is only followed if no patch or redirect happened.
I'm pretty sure this is also what LiveView does.
These two clauses match first:
defp maybe_redirect({:error, {:redirect, %{to: path}}}, session) do
defp maybe_redirect({:error, {:live_redirect, %{to: path}}} = result, session) do
So, given
<form phx-trigger-action={@trigger_submit} phx-change="redirect">
handle_event("redirect", _, socket) do
socket
|> push_navigate(to: "/elsewhere")
|> assign(:trigger_submit: true)
end
a change to the form will cause a redirect to /elsewhere
. And ignore the phx-trigger-action
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Double checked the actual behaviour:
redirect
: wins over phx-trigger-action (✅ this PR is ok)navigate
: wins over phx-trigger-action (✅ this PR is ok)patch
: is executed before phx-trigger-action, both are applied (✅ this PR is ok)
So I think we're fine.
You're right in that phx-trigger-action
is given priority over maybe_put_patch_path
.
But if there's a phx-trigger-action
, there's no point in updating the session.current_path
, because we're about to POST to another path anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once again, running the same test against an actual browser as well as the Live
driver would give peace of mind here :).
session.conn | ||
|> PhoenixTest.Static.build() | ||
|> PhoenixTest.Static.submit_form(form.selector, form_data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would imagine our implementation here is good. But I haven't done stuff with phx-trigger-action
, so want to ask. Do you know if we should be using LiveViewTest's follow_trigger_action
function to get the method and data to send?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the follow_trigger_action
, we should be fine.
It does the same things we're doing (ensure phx-trigger-action
attr present, then use method
and action
to HTTP submit the form).
Should we use follow_trigger_action
anyway?
Maybe.
In future the implementations might drift apart (theoretically, not saying it's likely).
Using follow_trigger_action
under the hood would prevent that.
No, rather be consistent with how we submit static forms from LiveViews
We have a precedent in PhoenixTest: static form submits from a LiveView (without phx-trigger-action).
phoenix_test/lib/phoenix_test/live.ex
Lines 299 to 302 in d62c264
Form.has_action?(form) -> | |
session.conn | |
|> PhoenixTest.Static.build() | |
|> PhoenixTest.Static.submit_form(selector, form_data) |
For that we could use LiveViewTest.submit_form
. Which uses the same helper function as LiveViewTest.follow_trigger_action
.
For the sake of simplicity (my interpretation) we don't do that and rather just call the Static driver directly.
test/phoenix_test/live_test.exs
Outdated
|> fill_in("Trigger action", with: "engage") | ||
|> submit() | ||
|> assert_has("#form-data", text: "hidden: included") | ||
|> assert_has("#form-data", text: "trigger_action: engage") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉
<label>Trigger action <input type="text" name="trigger_action" /></label> | ||
</form> | ||
|
||
<button phx-click="trigger-form">Trigger from elsewhere</button> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
This reverts commit e2dd5b4.
7b1d975
to
d62c264
Compare
Closes #47