Skip to main content
Ben Nadel at cf.Objective() 2010 (Minneapolis, MN) with: Pat Santora
Ben Nadel at cf.Objective() 2010 (Minneapolis, MN) with: Pat Santora

Including Inline Turbo-Stream Actions In Hotwire And Lucee CFML

By
Published in , Comments (1)

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 append, prepend, replace, and 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 <turbo-stream> elements.

Here's my main ColdFusion page - it includes a Div with id="messages". This Div will be mutated / transformed by the various inline <turbo-stream> directives.

<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>
view raw index.cfm hosted with ❤ by GitHub

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>
view raw frame.cfm hosted with ❤ by GitHub

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:

All three turbo-stream mutations have been applied to the DOM, showing three messages inside the messages container.

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.

Reader Comments

Post A Comment — I'd Love To Hear From You!

Markdown formatting: Basic formatting is supported: bold, italic, blockquotes, lists, fenced code-blocks. Read more about markdown syntax »
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.
Cancel
I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel