ColdFusion Mad Libs - Part II

ColdFusion Mad Libs ? Part 2 of 2

Wow! You?re back for more. I take it to mean you?re ready to take the next step in your Mad Libs application (if you have no idea what I?m talking about, stop reading right now and go check out the ColdFusion Mad Libs Part 1 tutorial)

In this tutorial, we?re going to allow the user to save the completed Mad Lib to a database. This will allow all of your site visitors to peruse all of the previous Mad Libs that have gone on before.

Wanna see it in action? http://charlie.griefer.com/madlibs_1_a.cfm.

First thing to do is create a database. It will be very simple?just one table with the following columns:

madlibID (autonumber, PK) *   
madlibDate (date/time)        
postedBy (text(30)) *         
madLib (memo) *               


* the datatypes above assume MS Access. Adjust accordingly depending on your DB.

Now onto the code.

The first template (madlibs_1.cfm) will not change. For that reason, I do not include it in this tutorial. It is shown in its entirety in the previous Mad Libs tutorial.

The second template (madlibs_2_a.cfm) needs only a few minor revisions (shown in bold).

madlibs_2.cfm (revised)
**************************************
<cfsilent>

<cfif NOT structKeyExists(form,
'ff_1')>
    <cflocation url=
"madlibs_1.cfm" addtoken="no" />
    <cfabort />
</cfif>

</cfsilent>
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>

<html xmlns=
"http://www.w3.org/1999/xhtml">
<head>
<title>
Untitled</title>
<meta http-equiv=
"Content-Type" content="text/html;charset=utf-8" />

<style type="text/css">
    body, input { font-family:verdana,arial,helvetica; font-size:11px; }
    b { color:#ff0000; font-variant:small-caps; background-color:#ffffcc; }
    h3 { color:#0000cc; font-size:14px; font-weight:bold; text-decoration:underline; }
    a { color:#0000ff; text-decoration:underline; }
    a:hover { color:#ff0000; text-decoration:none; }
</style>
</head>

<body>

<h3>
Your Mad Lib:</h3>

<cfoutput>
<cfsavecontent variable="madlib">

<b>#form.ff_1#</b> and <b>#form.ff_2#</b> went up the <b>#form.ff_3#</b> to <b>#form.ff_4#</b> a pail of <b>#form.ff_5#</b>.
<br />
<b>#form.ff_1#</b> fell down and broke his <b>#form.ff_6#</b> and <b>#form.ff_2#</b> came <b>#form.ff_7#</b> after.
</cfsavecontent>
</cfoutput>


<cfoutput>#variables.madlib#</cfoutput>

<form action="madlibs_3_a.cfm" method="post">
<cfoutput><input type="hidden" value="#replace(variables.madlib, '"', '""', 'all')#" name="madlib" /></cfoutput>
<input type="text" value="Enter Your Name" name="postedBy" />
<input type=
"submit" value="add to hall of fame" />
</form>

<br /><br />

<a href="madlibs_1_a.cfm">play again</a>

</body>
</html>

*************************************

What we?ve done differently is save the output of the mad lib into a variable (named madlib) using the <cfsavecontent> tag. 

We then output it to the screen (a simple <cfoutput>#variables.madlib#</cfoutput>, and we then have a form, which contains one hidden form field. That hidden form field contains the mad lib content. And just to be safe, we are going to make sure there are no double-quotes within the Mad Lib content (this would break the form). So we use the ColdFusion replace() function to swap all double-quotes with doubled-up double quotes (the CF method of escaping double quotes). We are then going to submit this information to madlibs_3_a.cfm, which will insert the mad lib into our database.

madlibs_3.cfm
**************************************
<cfsilent>

<cfif NOT structKeyExists(form,
'madlib')>
    <cflocation url=
"madlibs_1_a.cfm" addtoken="no" />
    <cfabort />
</cfif>

<cfquery name=
"insertMadLib" datasource="charlieSQL">
    INSERT INTO madLibs (
                            madLibDate,
                            postedBy,
                            madLib
                        )
                        VALUES (
                            <cfqueryparam value=
"#createODBCDate(now())#" cfsqltype="cf_sql_timestamp">,
                            <cfqueryparam value=
"#form.postedBy#" cfsqltype="cf_sql_char">,
                            <cfqueryparam value=
"#replace(form.madlib, '""', '"', 'all')#" cfsqltype="cf_sql_longvarchar">
                        )
</cfquery>

</cfsilent>
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>

<html xmlns=
"http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta http-equiv=
"Content-Type" content="text/html; charset=utf-8" />

<style type="text/css">
    body { font-family:verdana,arial,helvetica; font-size:11px; }
</style>
</head>

<body>

<cfoutput>
Thanks for posting your Mad Lib, #form.postedBy#!

<br /><br />
<a href="madlibs_view_1.cfm">Click here to see all Mad Libs</a>
</cfoutput>

</body>
</html>

*******************************************

Again, a very straightforward template. As with madlibs_2.cfm, we first check to make sure that the user came from the form (if not, we redirect them back to madlibs_1_a.cfm).

We then insert the new Mad Lib into our database (if you?re unfamiliar with <cfqueryparam>, please view my tutorial on it?it should take all of 5 minutes). Note that we are using the replace() function again in order to switch the escaped double-quotes back to regular double-quotes.

Finally, we provide a link to a page where the user can view all of the Mad Libs that have been saved?shown below:

madlibs_view_1.cfm
*******************************************
<cfsilent>

<cfquery name=
"getMadLibs" datasource="charlieSQL">
   
SELECT *
    FROM madLibs
    ORDER BY madLibDate DESC
</cfquery>

<cfscript>

    /**
    * Removes HTML from the string.
    * 
    * @param string String to be modified. 
    * @return Returns a string. 
    * @author Raymond Camden (ray@camdenfamily.com) 
    * @version 1, December 19, 2001 
    */
   
function StripHTML(str) {
                 return REReplaceNoCase(str,"<[^>]*>","","ALL");
    }
</cfscript>



</cfsilent><?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>

<html xmlns=
"http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta http-equiv=
"Content-Type" content="text/html; charset=utf-8" />

<style type="text/css">
    body, td { font-family:verdana,arial,helvetica; font-size:11px; }
    a { color:#0000ff; text-decoration:underline; }
    a:hover { color:#ff0000; text-decoration:none; }
</style>
</head>

<body>


<table border="1">
    <tr>
        <td>
Date:</td>
        <td>
Posted By:</td>
        <td>
Mad Lib:</td>
    </tr>

    <cfoutput query="getMadLibs">
    <tr>
        <td><a href=
"madlibs_view_2.cfm?madlibID=#getMadLibs.madlibID#">#dateFormat(getMadLibs.madLibDate, 'mm/dd/yyyy')#</a></td>
        <td><a href=
"madlibs_view_2.cfm?madlibID=#getMadLibs.madlibID#">#postedBy#</a></td>
        <td><a href=
"madlibs_view_2.cfm?madlibID=#getMadLibs.madlibID#">#left(stripHTML(trim(getMadLibs.madlib)), 100)#...</a></td>
    </tr>

    </cfoutput>
</table>

<br /><br />

<a href="madlibs_1_a.cfm">back to Main Mad Libs page</a>

</body>
</html>


****************************************

What?s going on here? We first query our database table to get all of the Mad Libs records.

You?ll also see a User-Defined Function (UDF) courtesy of http://www.cflib.org. This UDF strips all HTML tags from the content passed to it. Because the Mad Lib content contains <b> tags (to indicate the user?s input), we need to strip those in order to display the value to the user.

In the table in the body, we output three columns. The first contains the date that the Mad Lib was submitted?the second column shows the name of the user that posted it?the third and final contains a ?teaser??it shows the first 100 characters of the Mad Lib content. All 3 columns link to a page (madlibs_view_2.cfm) where the user can see the full Mad Lib (note that we?re passing the madlibID in the URL).


madlibs_view_2.cfm
*****************************************
<cfsilent>

<cfif NOT structKeyExists(URL,
'madlibID')>
    <cflocation url=
"madlibs_1_a.cfm" addtoken="no" />
    <cfabort />
</cfif>

<cfquery name=
"getMadLib" datasource="charlieSQL">
   
SELECT *
    FROM madLibs
    WHERE madlibID = <cfqueryparam value="#URL.madLibID#" cfsqltype="cf_sql_integer">
</cfquery>

</cfsilent>
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>

<html xmlns=
"http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta http-equiv=
"Content-Type" content="text/html; charset=utf-8" />

<style type="text/css">
    body, td { font-family:verdana,arial,helvetica; font-size:11px; }
    b { color:#ff0000; font-variant:small-caps; background-color:#ffffcc; }
    a { color:#0000ff; text-decoration:underline; }
    a:hover { color:#ff0000; text-decoration:none; }
</style>
</head>

<body>

<cfoutput query="getMadLib">
<table>
    <tr>
        <td style=
"font-weight:bold; width:80px;">Posted By:&nbsp;</td>
        <td style=
"width:400px;">#getMadLib.postedBy#</td>
    </tr>
    <tr>
        <td style=
"font-weight:bold; width:80px;">Date:&nbsp;</td>
        <td style=
"width:400px;">#dateFormat(madLibDate, 'mm/dd/yyyy')#</td>
    </tr>
    <tr>
        <td colspan=
"2"><br /><br /></td>
    </tr>
    <tr>
        <td colspan=
"2">#madLib#</td>
    </tr>
</table>

</cfoutput>

<br /><br />

<a href="madlibs_view_1.cfm">back</a>

</body>
</html>

****************************************

Again, a very straightforward template. We first check to see that URL.madlibID was passed (if not, relocate the user to madlibs_1_a.cfm). We then query the database to get the selected Mad Lib, and finally, we display it (notice I also added a custom style for the <b> tag, which will show the ?user input? values more clearly).

Finally, we add a link allowing the user to go back to view all Mad Libs in the database.

That?s it! You?re now ready to unleash your Mad Libs application on an unsuspecting public.

A few final notes:

1) Mad Libs *is* a registered trademark. You might want to consider calling your application something else.
2) If you get a lot of entries in your database, your madlibs_view_1.cfm page might get a bit unruly. If that happens, consider using the previous/next records tutorial found here on easycfm.com.
3) Of course, be aware that you run the risk of displaying vulgar content on your site by allowing users to post their own content. If this is unacceptable to you, consider adding the following content to the madlibs_3.cfm template (new content in bold):

madlibs_3_a.cfm (modified to disallow certain language)
****************************************
<cfsilent>

<cfif NOT structKeyExists(form,
'madlib')>
    <cflocation url=
"madlibs_1.cfm" addtoken="no" />
    <cfabort />
</cfif>

<cfset variables.myBadWordList =
"xxxx, yyyy, zzzz" />

<cfset variables.badWords = 0>
<cfloop list=
"#variables.myBadWordList#" index="i"
>
    <cfif findNoCase(i, madLib)>
        <cfset variables.badWords = variables.badWords + 1>
    </cfif>
</cfloop>

<cfif variables.badWords EQ 0>


    <cfquery name="insertMadLib" datasource=
"charlieSQL">
       
INSERT INTO madLibs (
                            madLibDate,
                            postedBy,
                            madLib
                           )
                           VALUES (
                                <cfqueryparam value=
"#createODBCDate(now())#" cfsqltype="cf_sql_timestamp">,
                                <cfqueryparam value=
"#form.postedBy#" cfsqltype="cf_sql_char">,
                                <cfqueryparam value=
"#replace(form.madlib, '""', '"', 'all')#" cfsqltype="cf_sql_longvarchar">
                           
)
        </cfquery>
</cfif>

</cfsilent>
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>

<html xmlns=
"http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta http-equiv=
"Content-Type" content="text/html; charset=utf-8" />

<style type="text/css">
    body { font-family:verdana,arial,helvetica; font-size:11px; }
</style>
</head>

<body>


<cfoutput>
    <cfif NOT variables.badWords>

        Thanks for posting your Mad Lib, #form.postedBy#!
    <cfelse>
        Sorry, but your Mad Lib contained content that is not suitable for this site. 
    </cfif>

    <br /><br />
    <a href="madlibs_view_1.cfm">Click here to see all Mad Libs</a>
</cfoutput>


</body>
</html>


****************************************

Ok?let?s break this down.

First, we create a list of known ?objectionable words?:
<cfset variables myBadWordList = ?xxxx, yyyy, zzzz, aaaa?>
(yes, I know ?yyyy? is not objectionable?you?ll need to come up with your own list)

Second, we create a variable called badWords, and set it to 0.
<cfset variables badWords = 0>

Next, we loop over that list, looking for each element of the list in the madlib content. If we find one, we increment the value of variables.badWords by 1.

Once we?re done looping, if the value of variables.badWords is still 0, that means no objectionable words were found, and we can do our INSERT query.

In the body of the page, we also run a condition based on the value of variables.badWords. If it?s 0, we thank the user for their submission. If it?s greater than 0, we notify the user that their content contained objectionable word(s), and therefore were not added to the database.

As always, if you have any questions, feel free to contact me personally, or preferably on the easycfm.com forums (so everyone can benefit from the discussion)

All ColdFusion Tutorials By Author: Charlie Griefer (CJ)
  • CFSCRIPT Intro
    An introductory look at CFSCRIPT. Rules, some basic syntax, and a couple of examples of loops and conditional processing.
    Author: Charlie Griefer (CJ)
    Views: 46,873
    Posted Date: Saturday, January 18, 2003
  • ColdFusion Mad Libs - Part I
    A silly but fun time-waster that you can easily include on your Web site. You might be surprised at how addicting it can become :)
    Author: Charlie Griefer (CJ)
    Views: 27,666
    Posted Date: Thursday, May 29, 2003
  • ColdFusion Mad Libs - Part II
    You've finished the first Mad Libs tutorial, but you feel like there's something missing. Of course there is! You want to be able to save the final output to a database to let your visitors browse through other user's stories. Includes a bad-words filter for the more conservative among us :)
    Author: Charlie Griefer (CJ)
    Views: 22,839
    Posted Date: Thursday, May 29, 2003
  • to cfqueryparam or not to cfqueryparam
    It's been out there since ColdFusion 4.5...most of us have heard of it...few of us use it. Here are some compelling reasons why you should get into the habit of using the tag.
    Author: Charlie Griefer (CJ)
    Views: 34,135
    Posted Date: Thursday, May 29, 2003
  • Dynamic Column Output (Part One)
    Have you ever wanted to display your content in rows of 3 columns? If you ever wanted to specify the number of columns per row within your content, here's the tutorial for you.
    Author: Charlie Griefer (CJ)
    Views: 34,987
    Posted Date: Thursday, May 29, 2003
  • Dynamic Column Output (Part Two)
    This tutorial picks up where the Dynamic Columns tutorial left off, showing you how to not only output your data in a specified number of columns, but how to do it while still publishing well formed HTML.
    Author: Charlie Griefer (CJ)
    Views: 27,534
    Posted Date: Saturday, May 31, 2003
  • Remote File Management
    Manage text-based files on your server from any Web browser. Create a new file, edit a file, or delete a file. Can be a life saver if you're on the road, and find an error in some of your code that needs a quick fix.
    Author: Charlie Griefer (CJ)
    Views: 27,815
    Posted Date: Tuesday, June 3, 2003
  • Save your visitor's clickstreams
    A nifty little custom tag that will allow you to save a visitor's clickstream through your site, as well as display it back to them (with links). Did I really just say 'nifty'?
    Author: Charlie Griefer (CJ)
    Views: 25,608
    Posted Date: Monday, June 16, 2003
  • Grouping Output in CF
    How to group cfquery output in order to effectively display relational database data. Includes an overview of how to output nested groups as well.
    Author: Charlie Griefer (CJ)
    Views: 32,508
    Posted Date: Tuesday, June 17, 2003
  • arrays and structures - part 1
    part one of a three-part tutorial designed to gently introduce you to the world of complex variables.
    Author: Charlie Griefer (CJ)
    Views: 38,749
    Posted Date: Monday, August 11, 2003
  • arrays and structures - part 2
    part two of a three-part tutorial designed to gently introduce you to the world of complex variables.
    Author: Charlie Griefer (CJ)
    Views: 28,290
    Posted Date: Monday, August 11, 2003
  • arrays and structures - part 3
    part three of a three-part tutorial designed to gently introduce you to the world of complex variables.
    Author: Charlie Griefer (CJ)
    Views: 33,332
    Posted Date: Monday, August 11, 2003
  • JavaScript Form Validation
    Yes, I know we're a ColdFusion site...but ColdFusion does not live in a vacuum. We have to know SQL, HTML, CSS...and sometimes...JavaScript! This tutorial focuses on using JavaScript (in lieu of cfform) to create client side form validation (and explains why writing your own is better than using ).
    Author: Charlie Griefer (CJ)
    Views: 58,283
    Posted Date: Thursday, August 14, 2003
  • CF 'Best Practices'
    Some tips and techniques that I've picked up over the years. I don't maintain that these are 'official' or 'absolute'...they are simply my preference and things that have worked for me. I would like to share them here, and leave you to make the decision as to whether or not they fit in your 'code arsenal' :)
    Author: Charlie Griefer (CJ)
    Views: 35,637
    Posted Date: Friday, August 15, 2003
  • Helping users obtain their passwords
    Your site requires your visitors to log in. of course, some of your visitors are going to forget their passwords (ok, most will forget their passwords). You don't want them to have to send you an e-mail, and then wait for a response. They need immediate access.

    This tutorial shows two methods by which you can accomodate them.
    Author: Charlie Griefer (CJ)
    Views: 26,198
    Posted Date: Thursday, August 28, 2003
Download the EasyCFM.COM Browser Toolbar!