Created
March 1, 2023 14:02
-
-
Save bennadel/73b378209bc440660eca2802fbae182f to your computer and use it in GitHub Desktop.
Transcluding A Form Into A Turbo Frame Using Hotwire And Lucee CFML
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
component | |
output = false | |
hint = "I define the application settings and event handlers." | |
{ | |
// ... truncated code ... // | |
/** | |
* I get called once to initialize the request. | |
*/ | |
public void function onRequestStart() { | |
request.context = structNew() | |
.append( url ) | |
.append( form ) | |
; | |
request.isGet = ( cgi.request_method == "get" ); | |
request.isPost = ! request.isGet; | |
request.template = { | |
statusCode: 200, | |
statusText: "OK" | |
}; | |
// When Turbo Drive makes requests to the ColdFusion server, it will modify the | |
// HTTP request headers in two ways: | |
// | |
// 1. If the request is made in the context of a Turbo Frame, the ID of the frame | |
// will be included as the header, "Turbo-Frame". | |
// | |
// 2. If the request is a FORM submission, which can accept a Turbo Stream style | |
// response, a new type will be appended to the "Accept" header. | |
var headers = getHttpRequestData( false ).headers; | |
var turboFrame = ( headers[ "Turbo-Frame" ] ?: "" ); | |
request.turbo = { | |
isFrame: turboFrame.len(), | |
frame: turboFrame, | |
isStream: ( headers[ "Accept" ] ?: "" ).findNoCase( "text/vnd.turbo-stream.html" ) | |
}; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<cfscript> | |
param name="form.text" type="string" default=""; | |
errorMessage = ""; | |
if ( request.isPost ) { | |
try { | |
application.noteService.createNote( form.text.trim() ); | |
// If we are in Turbo Frame and can support a Turbo Stream response, then we | |
// will execute the REDIRECT using our custom Turbo Stream "visit" action. | |
if ( request.turbo.isFrame && request.turbo.isStream ) { | |
include "./create_stream.cfm"; | |
exit; | |
// If this is a normal top-level page action, then let's redirect back to the | |
// main page as per usual. | |
} else { | |
location( url = "index.htm", addToken = false ); | |
} | |
} catch ( any error ) { | |
errorResponse = application.errorService.getResponse( error ); | |
request.template.statusCode = errorResponse.statusCode; | |
request.template.statusText = errorResponse.statusText; | |
errorMessage = errorResponse.message; | |
} | |
} | |
</cfscript> | |
<cfmodule template="./tags/page.cfm"> | |
<cfoutput> | |
<h2> | |
Add Note | |
</h2> | |
<!--- | |
In order for this note creation form to be transcluded (in to the main page) | |
by Turbo Drive, we have to wrap it in a Turbo Frame that corresponds to the | |
lazy-loaded frame in the main page. For that, we'll use the frame ID that was | |
reported in the HTTP headers (to reduce duplication). | |
-- | |
NOTE: We are using target="_top" in this context so that if this page were | |
loaded directly (via the URL), it would operate as if it weren't in a frame. | |
---> | |
<turbo-frame | |
id="#encodeForHtmlAttribute( request.turbo.frame )#" | |
target="_top"> | |
<cfif errorMessage.len()> | |
<p class="error-message"> | |
#encodeForHtml( errorMessage )# | |
</p> | |
</cfif> | |
<form method="post" action="create.htm"> | |
<p> | |
<input type="text" name="text" size="40" autofocus /> | |
</p> | |
<p> | |
<button type="submit"> | |
Add Note | |
</button> | |
<!--- | |
This cancel button will be hidden (via the CSS class) when it is | |
transcluded into the main page. | |
---> | |
<a href="index.htm" class="hide-if-transcluded"> | |
Cancel | |
</a> | |
<!--- | |
If this form is being transcluded into the main page, and it has | |
an error message, let's show a button to clear / reset the form | |
(to remove the error message). Depending on the type of form you | |
have, this may not be necessary. | |
---> | |
<cfif ( request.turbo.isFrame && errorMessage.len() )> | |
<a href="create.htm" data-turbo-frame="_self"> | |
Reset | |
</a> | |
</cfif> | |
</p> | |
</form> | |
</turbo-frame> | |
</cfoutput> | |
</cfmodule> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<cfcontent type="text/vnd.turbo-stream.html; charset=utf-8" /> | |
<cfoutput> | |
<!--- Refresh the create form Turbo Frame. ---> | |
<turbo-stream | |
action="visit" | |
data-url="create.htm" | |
data-frame="create-frame"> | |
</turbo-stream> | |
<!--- Refresh the list of notes Turbo Frame. ---> | |
<turbo-stream | |
action="visit" | |
data-url="index.htm" | |
data-frame="notes-list"> | |
</turbo-stream> | |
</cfoutput> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<cfscript> | |
notes = application.noteService.getNotes().reverse(); | |
</cfscript> | |
<cfmodule template="./tags/page.cfm"> | |
<cfoutput> | |
<h2> | |
Notes | |
</h2> | |
<!--- | |
This Turbo Frame is LAZY LOADED and will inline the create-note form. The | |
static contents of the form will be rendered as a fallback while the remote | |
template is being loaded. | |
-- | |
NOTE: The "transcluded" CSS class is included to help us hide elements of the | |
form after it has been loaded and inlined by Turbo Drive. | |
---> | |
<turbo-frame | |
id="create-frame" | |
src="create.htm" | |
data-turbo-permanent | |
class="transcluded"> | |
<p> | |
<a href="create.htm">Add Note</a> | |
</p> | |
</turbo-frame> | |
<!--- | |
This Turbo Frame gives us a target to RELOAD after a new note has been added. | |
The RELOAD functionality will be implemented as a custom Turbo Stream action. | |
---> | |
<turbo-frame id="notes-list"> | |
<ul> | |
<cfloop item="note" array="#notes#"> | |
<li> | |
#encodeForHtml( note.text )# | |
— | |
<a | |
href="delete.htm?id=#encodeForUrl( note.id )#" | |
data-turbo-method="delete" | |
data-turbo-confirm="Delete this note?"> | |
Delete | |
</a> | |
</li> | |
</cfloop> | |
</ul> | |
<cfif notes.len()> | |
<p> | |
<a | |
href="clear.htm" | |
data-turbo-method="delete" | |
data-turbo-confirm="Delete all notes?"> | |
Clear all notes | |
</a> | |
</p> | |
</cfif> | |
</turbo-frame> | |
</cfoutput> | |
</cfmodule> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Import core modules. | |
import * as Turbo from "@hotwired/turbo"; | |
import { StreamActions } from "@hotwired/turbo"; | |
// ----------------------------------------------------------------------------------- // | |
// ----------------------------------------------------------------------------------- // | |
/** | |
* I support Turbo.visit() stream actions. | |
*/ | |
StreamActions.visit = function() { | |
var url = this.dataset.url; | |
var action = ( this.dataset.action || "advance" ); | |
var frame = ( this.dataset.frame || undefined ); | |
Turbo.visit( | |
url, | |
{ | |
action: action, | |
frame: frame | |
} | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.transcluded { | |
.hide-if-transcluded { | |
display: none ; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<turbo-frame | |
id="create-frame" | |
src="create.htm" | |
data-turbo-permanent | |
class="transcluded"> | |
<!--- Static content ---> | |
</turbo-frame> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<a href="index.htm" class="hide-if-transcluded"> | |
Cancel | |
</a> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment