select-your-own-seat

Expand History Expand History
Collapse History Collapse History

Progressively enhance navigating to seats#show

The application’s seats#show action renders the details of a Seat within the context of a modally shown <dialog> element that is overlaid on top of that Seat record’s associated Floor record within the Seat map.

During a full page visit to the seats#show action via a direct GET /venues/:venue_id/floors/:floor_id/seats/:id request, that action fetches the entire set of associated Seat records for a given Floor, and renders the entire set into the template.

In this application’s case, that’s between 1,300 and 1,500 records that are fetched, and as many (or more) corresponding <svg> elements sent to the browser.

As a means of mitigating that load when navigating to the seats#show action from within JavaScript-capable browsing environments, this commit introduces the notion of a Turbolinks “fragment”.

The lifecycle of a “fragment” navigation

Without taking explicit steps to opt-into fragment navigation, all <a> elements that are not annotated with [data-turbolinks="false"] attributes will continue to behave as Turbolinks-enabled links.

When an <a> element declares the [data-turbolinks-fragment] attribute, mark the triggered Turbolinks-powered request to be a “fragment” request.

Our Stimulus controller attaches event listeners throughout the resulting sequence of events:

  1. When the initial turbolinks:click event fires, check the <a> element for an attribute for the value of its [data-turbolinks-fragment] attribute. When present, annotate the <body> element with that value as the [data- turbolinks-fragment-request] attribute.

  2. When the turbolinks:request-start event fires, read the <body data-turbolinks-fragment-request> attribute’s value, passing it along to the event’s XMLHttPRequest instance under the X-Turbolinks-Fragment header.

  3. When the turbolinks:before-render event fires, merge the server’s fragmented response into the current page, before Turbolinks populates its page cache and finishes the navigation.

    To ensure that the “fragment”‘s response HTML is injected into the incoming <body> element, merge its contents from the response into the current <body> element, and then re-write the turbolinks:before-render event’s event.data.newBody to reflect the updated current, re-written <body> element.

  4. The modifications to the turbolinks:before-render event’s newBody are written to Turbolinks’ page cache, and are seamlessly re-integrate into the remainder of the Turbolinks navigation

The server-side component

When an incoming request declares the X-Turbolinks-Fragment header, set the request’s variant to :fragment.

In this commit’s case, the seats#show action will skip rendering the seats/index template by guarding it with a request.variant.fragment? check.