Skip to main content
Ben Nadel at cf.Objective() 2014 (Bloomington, MN) with: Jeff McDowell
Ben Nadel at cf.Objective() 2014 (Bloomington, MN) with: Jeff McDowell

Dynamically Adding Stimulus Controllers To Static Content Using Hotwire And Lucee CFML

By
Published in ,

As I'm digging into the Hotwire framework, I'm trying to keep an eye on how I might eventually convert this ColdFusion blog over to using it. And, one of the things that I currently have to contend with (on this blog) is progressively enhancing the "static content" within each blog post (ex, resizing code-blocks on mouseenter). The "Stimulus way" seeks to create small, targeted controllers instead of large, over-reaching "page" controllers. As such, I wanted to see if I can dynamically attach Stimulus Controllers to targeted elements within my static content.

View this code in my ColdFusion + Hotwire Demos project on GitHub.

To test this, I created a Stimulus controller that does little more than log its connect() callback and add a CSS class to its host element:

// Import core modules.
import { Application } from "@hotwired/stimulus";
import { Controller } from "@hotwired/stimulus";
import * as Turbo from "@hotwired/turbo";

// ----------------------------------------------------------------------------------- //
// ----------------------------------------------------------------------------------- //

class DynamicController extends Controller {

	/**
	* I get called whenever this controller instance is bound to a host element.
	*/
	connect() {

		console.group( "Dynamic Controller" );
		console.log( "Connected!" );
		console.log( this.element );
		console.groupEnd();

		this.element.classList.add( "enhanced" );

	}

}

// ----------------------------------------------------------------------------------- //
// ----------------------------------------------------------------------------------- //

window.Stimulus = Application.start();
// When not using the Ruby On Rails asset pipeline / build system, Stimulus doesn't know
// how to map controller classes to data-controller attributes. As such, we have to
// explicitly register the Controllers on Stimulus startup.
Stimulus.register( "dynamic-controller", DynamicController );

Then, I created a ColdFusion page that renders some static content alongside a link to dynamically add the dynamic-controller identifier to an element on the page:

<cfmodule template="./tags/page.cfm">
	<cfoutput>

		<h2>
			Welcome to My Site
		</h2>

		<div id="dyno">
			This is static content.
		</div>

		<p>
			<a href="javascript:( dyno.dataset.controller = 'dynamic-controller' );void(0);">
				Attach Controller
			</a>
		</p>

	</cfoutput>
</cfmodule>

Hotwire Stimulus works by attaching a MutationObserver to the active page. Hotwire treats the DOM (Document Object Model) as the "source of truth" for the state of the application; and, it uses the MutationObserver to monitor and respond to changes in this application state. My hope here is that by setting the data-controller attribute, the MutationObserver will trigger Stimulus to instantiate the registered Controller and attach it to the DOM.

Now, if we open up our ColdFusion application and click on the "Attach Controller" link, we get the following output:

As you can see, once we set the data-controller attribute to dynamic-controller, Stimulus sees the change and, in response, instantiates our DynamicController class and attaches it to the host element!

This is great! I can totally use this dynamic Stimulus behavior to progressively enhance static content being served up from my ColdFusion server! This also means that I can very likely baby-step my way to using Hotwire by creating thin Stimulus controllers that do nothing but wire-up my existing JavaScript behaviors (that is, before I move the entirety of the logic into Stimulus controllers).

Want to use code from this post? Check out the license.

Reader Comments

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

Post a Comment

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