-
Notifications
You must be signed in to change notification settings - Fork 430
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
Expand rendering capabilities of <turbo-frame>
#146
Closed
Closed
Commits on Nov 25, 2021
-
Scope
willRender
toPageRenderer
onlyThe `willRender` property introduced to the generic `Renderer<E, S>` only applies to the `PageRenderer` specialized sub-class. This commit removes it from the root class and declares a `PageRenderer.constructor()` method to accept and assign it.
Configuration menu - View commit details
-
Copy full SHA for 5254834 - Browse repository at this point
Copy the full SHA 5254834View commit details -
Extract
FrameVisit
to driveFrameController
The problem --- Programmatically driving a `<turbo-frame>` element when its `[src]` attribute changes is a suitable end-user experience in consumer applications. It's a fitting black-box interface for the outside world: change the value of the attribute and let Turbo handle the rest. However, internally, it's a lossy abstraction. For example, the `FrameRedirector` class listens for page-wide events `click` and `submit` events, determines if their targets are meant to drive a `<turbo-frame>` element by: 1. finding an element that matches a clicked `<a>` element's `[data-turbo-frame]` attribute 2. finding an element that matches a submitted `<form>` element's `[data-turbo-frame]` attribute 3. finding an element that matches a submitted `<form>` element's _submitter's_ `[data-turbo-frame]` attribute 4. finding the closest `<turbo-frame>` ancestor to the `<a>` or `<form>` Once it finds the matching frame element, it disposes of all that additional context and navigates the `<turbo-frame>` by updating its `[src]` attribute. This makes it impossible to control various aspects of the frame navigation (like its "rendering" explored in [hotwired#146][]) outside of its destination URL. Similarly, since a `<form>` and submitter pairing have an impact on which `<turbo-frame>` is navigated, the `FrameController` implementation passes around a `HTMLFormElement` and `HTMLSubmitter?` data clump and constantly re-fetches a matching `<turbo-frame>` instance. Outside of frames, page-wide navigation is driven by a `Visit` instance that manages the HTTP lifecycle and delegates along the way to a `VisitDelegate`. It also pairs calls to visit with a `VisitOption` object to capture additional context. The proposal --- This commit introduces the `FrameVisit` class. It serves as an encapsulation of the `FetchRequest` and `FormSubmission` lifecycle events involved in navigating a frame. It's implementation draws inspiration from the `Visit`, `VisitDelegate`, and `VisitOptions` pairing. Since the `FrameVisit` knows how to unify both `FetchRequest` and `FormSubmission` hooks, the resulting callbacks fired from within the `FrameController` are flat and consistent. Extra benefits --- The biggest benefit is the introduction of a DRY abstraction to manage the behind the scenes HTTP calls necessary to drive a `<turbo-frame>`. With the introduction of the `FrameVisit` concept, we can also declare a `visit()` and `submit()` method to the `FrameElementDelegate` in the place of other implementation-specific methods like `loadResponse()` and `formSubmissionIntercepted()`. In addition, these changes have the potential to close [hotwired#326][], since we can consistently invoke `loadResponse()` across `<a>`-click-initiated and `<form>`-submission-initiated visits. To ensure that's the case, this commit adds test coverage for navigating a `<turbo-frame>` by making a `GET` request to an endpoint that responds with a `500` status. [hotwired#146]: hotwired#146 [hotwired#326]: hotwired#326
Configuration menu - View commit details
-
Copy full SHA for 0e95df6 - Browse repository at this point
Copy the full SHA 0e95df6View commit details -
Expand rendering capabilities of
<turbo-frame>
Problem --- Navigating a `<turbo-frame>` element always renders the new content by updating the contents with the children from the response. This limits the utility of `<turbo-frame>` in scenarios involving pagination driven by "next" and "previous" page links. Solution --- Add support for `<turbo-frame rendering="...">`, `<a data-turbo-rendering="...">`, `<form data-turbo-rendering="...">`, and `<button data-turbo-rendering="...">` where the value of `[rendering]` and `[data-turbo-rendering]` is one of the values that `<turbo-stream action="...">` supports. By default, `<turbo-frame>` elements will continue to render render with the behavior equivalent to a `<turbo-stream action="update">` element. This commit extends that support to also include the other actions: * `after` will insert the contents of the response frame after the request frame * `append` will extract the contents out of the response frame and append them into the request frame * `before` will insert the contents of the response frame before the request frame * `prepend` will extract the contents out of the response frame and append them into the request frame * `replace` will extract the contents out of the response frame, remove the request frame, and inject the extracted contents in its place (conceptually similar to setting `outerHTML`) * `remove` will remove the request frame, and ignore the contents of the response frame This enables behaviors that might have been achievable with `GET`-request powered Turbo Stream responses. For example, in-place pagination could be achieved with `rendering="prepend"` or `rendering="append"`: ```html <!-- current HTML --> <turbo-frame id="posts"> <article id="article_1"><!-- contents --></article> <!-- articles 2-9 --> <article id="article_10"><!-- contents --></article> <a href="/posts?page=2" data-turbo-rendering="append">Next page</a> </turbo-frame> <!-- response HTML --> <turbo-frame id="posts"> <article id="article_11"><!-- contents --></article> <a href="/posts?page=3" data-turbo-rendering="append">Next page</a> </turbo-frame> <!-- HTML after the request --> <turbo-frame id="posts"> <article id="article_1"><!-- contents --></article> <!-- articles 2-9 --> <article id="article_10"><!-- contents --></article> <a href="/posts?page=2" data-turbo-rendering="append">Next page</a> <article id="article_11"><!-- contents --></article> <a href="/posts?page=3" data-turbo-rendering="append">Next page</a> </turbo-frame> ``` Through the power of a CSS rules utilizing `:last-of-type`, we can hide the pagination links: ```css #posts a { display: none; } #posts a:last-of-type { display: block; } ```
Configuration menu - View commit details
-
Copy full SHA for b7f1a72 - Browse repository at this point
Copy the full SHA b7f1a72View commit details
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.