Including Inline Turbo-Stream Actions In Hotwire And Lucee CFML
In my first exploration of Turbo Streams in Hotwire, I was generating a dedicated response of type,
text/vnd.turbo-stream.html, which was being returned within a Form
POST response. Based on the Turbo documentation, I had thought that this was the only way in which to use Turbo Streams. But, I recently came across a post on the Hotwire developer forum where people were talking about including Turbo Stream elements inline with any kind of response (top-level page or Turbo Frame). This is a very interesting proposition that I wanted to explore in Lucee CFML.
View this code in my ColdFusion + Hotwire Demos project on GitHub.
As I discussed in my previous post, Turbo Stream elements define actions for Turbo Drive to perform in response to navigation events. The default actions are all DOM (Document Object Model) transformations, like
update. But, Turbo allows you to define custom actions which might include features such as logging and redirection.
ASIDE: I haven't explored it yet, but the Ruby on Rails community seems to be favoring TurboPower, a 3rd-party set of Turbo Stream actions that includes interaction with cookies, styles, history, frames, etc.
To explore the definition and consumption of inline
<turbo-stream> elements, I've created a very simple ColdFusion application. It has a main page and an asynchronously-loaded
<turbo-frame>. Both the main page and the async frame will provide responses that have embedded
Here's my main ColdFusion page - it includes a Div with
id="messages". This Div will be mutated / transformed by the various inline
<cfmodule template="./tags/page.cfm"> <cfoutput> <h2> Welcome to My Site </h2> <div id="messages"> This content will be replaced by the TURBO-STREAM actions below. </div> <turbo-frame id="async-frame" src="frame.htm"> <!--- Will be loaded asynchronously. ---> </turbo-frame> <!--- ---------------------------------------------------------------------- ---> <!--- ---------------------------------------------------------------------- ---> <!--- Notice that the following Turbo-Stream elements are NOT part of a traditional "text/vnd.turbo-stream.html" response - they are being defined right inline with the page content. On load, Turbo Drive will locate them, apply the DOM (Document Object Model) transformations, and then remove them. ---> <turbo-stream action="update" target="messages"> <template> <p class="inline-action"> This is the first message. I have <strong>reset</strong> the messages container. </p> </template> </turbo-stream> <turbo-stream action="append" target="messages"> <template> <p class="inline-action"> This is the second message. </p> </template> </turbo-stream> </cfoutput> </cfmodule>
As you can see, there are two inline Turbo Stream elements: one that resets (
update) the messages content with a first message; and, one that appends a second message. On top of that, we also have our asynchronously loaded Turbo Frame:
<turbo-frame id="async-frame"> <p> This is the async FRAME content. </p> <!--- In order for these inline Turbo-Stream elements to be picked up and applied to the live document, they have to be included inside of the Turbo-Frame element. Otherwise, they will not be transcluded into the calling page and will, therefore, be de facto discarded. ---> <turbo-stream action="append" target="messages"> <template> <p class="inline-action inline-action--async"> This was injected via the async <strong>Turbo-Frame</strong> response. </p> </template> </turbo-stream> </turbo-frame>
Again, this Turbo Frame includes an inline
<turbo-stream> element representing a transformation of the
messages container. Note that Turbo Frames are rendered based on a corresponding
id attribute. As such, everything outside of the Turbo Frame will be discarded. This means that our Turbo Stream directives must be inside the rendered frame content.
Now, if we run our main ColdFusion page, we get the following output:
As you can see, all of the message transformations defined by our inline
<turbo-stream> elements have all been applied to the DOM!
This is a really slick feature of Hotwire - I'm surprised that it isn't made more obvious in the documentation. I can see this being quite helpful in updating transient parts of the DOM in response to actions taken by the user.
Want to use code from this post? Check out the license.
Here's a quick follow-up on creating custom Turbo Stream actions:
In that exploration, I create a
visitaction which invokes a
Turbo.visit()call under the hood.
Post A Comment — ❤️ I'd Love To Hear From You! ❤️
Post a Comment →