-
Notifications
You must be signed in to change notification settings - Fork 429
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
Fix form in nested turbo-frame with target=_top #399
Conversation
@seanpdoyle - check my logic on this. |
if (event.target instanceof HTMLFormElement) { | ||
const form = event.target | ||
const form = event.target | ||
if (form instanceof HTMLFormElement && form.closest("turbo-frame, html") == this.element) { |
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.
What is the significance of the second html
selector?
Also, if the frame that the <form>
is nested within matches turbo-frame[disabled]
, wouldn't we want events to bubble past it to the outer frame?
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.
According to the commit message, the element.closest("turbo-frame, html") == this.element
is lifted directly from the LinkInterceptor
. The [disabled]
checks happen within the delegates' shouldInterceptLinkClick
and shouldInterceptFormSubmission
, which on further consideration feels more aligned with the delegator pattern than leaking that concept up into the observer layer.
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.
What is the significance of the second html selector?
I had the same question about the logic in link_interceptor.ts#L58, but figured I'd follow the same pattern to be safe.
Also, if the frame that the
is nested within matches turbo-frame[disabled], wouldn't we want events to bubble past it to the outer frame?
I also wondered this, and do not know the answer. Under what circumstances are a frame disabled?
I saw you were the last one that worked with this code, which is why I pinged you for review.
The [disabled] checks happen within the delegates' shouldInterceptLinkClick and shouldInterceptFormSubmission, which on further consideration feels more aligned with the delegator pattern than leaking that concept up into the observer layer.
I originally placed the code in shouldInterceptFormSubmission
, but then went this direction after seeing how LinkInterceptor handled it.
private shouldInterceptNavigation(element: Element, submitter?: Element) {
const id = submitter?.getAttribute("data-turbo-frame") || element.getAttribute("data-turbo-frame") || this.element.getAttribute("target")
- if (!this.enabled || id == "_top") {
+ if (!this.enabled || id == "_top" || this.element != element.closest("turbo-frame") || id == "_top") {
}
return false
}
It seemed odd to me to handle it one way for links and another for forms when the overall concept is very similar. Almost seems like there's some shared code that should exist here.
FYI, I've seen this happen a couple of times with turbo, where updates are made to link logic, but not forms or the other way around.
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.
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've got a piece of functionality ready to go that relies on the issue being fixed, so this PR getting merged would be helpful to me. Are those two PRs a prerequisite for this one to go through? I should also ask whether there's anything I can do to help progress this further.
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.
@boardfish they're parallel concerns in my mind, and shouldn't block this one (#399).
src/tests/functional/frame_tests.ts
Outdated
@@ -75,6 +75,17 @@ export class FrameTests extends TurboDriveTestCase { | |||
this.assert.notOk(await this.hasSelector("#nested-child")) | |||
} | |||
|
|||
async "test following a form within a nested frame with target top"() { |
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.
A test for a form
with data-turbo-frame="_top"
might also be helpful here: https://turbo.hotwired.dev/reference/frames#frame-with-overwritten-navigation-targets
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.
add the additional test
#396
The class LinkInterceptor checks if the target is a valid Element and if the closest turbo-frame matches the current turbo-frame.
The FormInterceptor checks if the target is a HTMLFormElement, but does not check if the closest turbo-frame matches the current turbo-frame.
As a result, a nested turbo-frame will bubble up to the parent turbo-frame when the turbo-frame is not disabled or the target == "_top". The parent turbo-frame should not be handling form events nested in a child turbo-frame.