Shimju asks:
How can we create Javascript widget from a coldfusion query.
In more detail, we will ask our website visitors to signup for using our widget. While doing so, they will be asked to select which news categories they are interested and how many news they want to display on their site. And once user clicks submit button a Javascript code should generate and they can place it on their websites for appearing our widget with selected number of news from subscribed categories. Please advice how to do this?
This is fairly simple. You are really talking about two particular things here. Building a JavaScript widget driven by URL parameters, and building a front-end "designer" to let folks get the JavaScript code. I'm going to focus on the widget aspect as the front end part you mention is rather trivial once you have the widget built.
The process to embed a widget from another site is simple. I can embed a JavaScript file from Adobe by doing this:
<script src="http://www.adobe.com/foo.js"></script>
Since the browser doesn't care about the file extension, I could also do:
<script src="http://www.adobe.com/foo.cfm"></script>
As long as the script outputs valid JavaScript code, it will work just fine. You specifically talked about embedding news, so lets look at a simple example of this. First I'll build a random query:
<cfset news = queryNew("articleurl,title,category")>
<cfloop index="x" from="1" to="20">
<cfset newurl = "http://someurl.com/#x#.html">
<cfset newtitle = "News Story #x#">
<cfset newcategory = listGetAt("Cats,Dogs",randRange(1,2))>
<cfset queryAddRow(news)>
<cfset querySetCell(news, "articleurl", newurl)>
<cfset querySetCell(news, "title", newtitle)>
<cfset querySetCell(news, "category", newcategory)>
</cfloop>
Obviously this stuff would be a "real" database hit. Next I want to allow folks to filter both by a max number of entries as well as by category:
<cfparam name="url.max" default="10">
<cfparam name="url.category" default="">
<!--- handle getting right data --->
<cfquery name="news" dbtype="query" maxrows="#url.max#">
select *
from news
<cfif url.category is not "">
where lower(category) = <cfqueryparam cfsqltype="cf_sql_varchar" value="#lcase(url.category)#">
</cfif>
</cfquery>
Nothing too complex about that so I won't cover it in detail. I will mention one tip about maxrows however. If you pass a maxrows of -1, it is the same as all rows. This is a handy way to use maxrows and still allow folks to not specify a maximum number of rows.
Ok, so far so good. Now we need to output some JavaScript. If I just output simple text, the browser won't know what to do with it. I chose to use document.write. This is probably not the best idea, but it works. I'm definitely open to better alternatives though. Here is my output:
<cfoutput>
document.write("<table border='1' bgcolor='yellow'><tr><td>");
<cfloop query="news">
document.write("<a href='#articleurl#'>#title#</a> [#category#]<br>");
</cfloop>
document.write("</table>");
</cfoutput>
As you can see, I used a simple table to output the query. Now if you wanted to embed this on your site, you would just use this syntax to get 4 Cat stories
<script src="http://192.168.1.102/test2.cfm?max=4&category=cats"></script>
Or this syntax to get 10 stories on dogs and cats.
<script src="http://192.168.1.102/test2.cfm"></script>
Pretty simple stuff, but you can make it more complex of course. Does anyone have any examples of this they would like to share?
Archived Comments
This is cool. I always had my cfm page cffile the new js file. This an awesome solution!
-Randy
This is also the [ugly and not recommended] way to handle AJAX. Create a new script block, have it call a CF page that generates some JavaScript with the dynamic values. Very clunky now with all the frameworks (and CF8), but back in the day, it was pretty cool. :-)
Isn't this approach particularly handy for client/widget kind of scenario since the AJAX domain security doesn't apply? I haven't played with it for awhile, but pretty sure.
Here is an alternate solution that can be used with a single document.write call:
data.cfm
<cfset news = queryNew("articleurl,title,category")>
<cfloop index="x" from="1" to="20">
<cfset newurl = "http://someurl.com/#x#.html">
<cfset newtitle = "News Story #x#">
<cfset newcategory = listGetAt("Cats,Dogs",randRange(1,2))>
<cfset queryAddRow(news)>
<cfset querySetCell(news, "articleurl", newurl)>
<cfset querySetCell(news, "title", newtitle)>
<cfset querySetCell(news, "category", newcategory)>
</cfloop>
<cfparam name="url.max" default="10">
<cfparam name="url.category" default="">
<!--- handle getting right data --->
<cfquery name="news" dbtype="query" maxrows="#url.max#">
select *
from news
<cfif url.category is not "">
where lower(category) = <cfqueryparam cfsqltype="cf_sql_varchar" value="#lcase(url.category)#">
</cfif>
</cfquery>
<cfsavecontent variable="result">
<cfoutput>
<div id="myDiv">
<table border="1" bgcolor="yellow">
<cfloop query="news">
<tr>
<td><a href='#articleurl#'>#title#</a> [#category#]</td>
</tr>
</cfloop>
</table>
</div>
</cfoutput>
</cfsavecontent>
<cfoutput>document.write('#jsStringFormat(result)#')</cfoutput>
index.cfm
<script src="http://localhost/data.cfm?max=4"></script>
Now load in the browser and make sure the correct url is pointing in the js call.
I have been looking for something like this forever! Thanks so much!!!!