Products

Products
Viewing By Category : JavaScript/Ajax / Main
September 9, 2009

ColdFusion with Javascript with ColdFusion

I had a situation where I wanted to pass a query param to a ColdFusion page that would use it to find a record in a cfquery then pass that record to a Javascript function used to display that record in that ColdFusion page. Thats a lot to say all at once. Let me see if I can explain it better.

My ColdFusion page displays a list of private messages for a user in their user account. This list is at the top of the page and shows date, time, sender, and subject. When the user clicks on the subject of any message in the list, Javascript Ajax is used to fetch the message details from a component and display the message fully below the list, kind of like an email program. Also when the page loads, as a default the first message in the list is automatically passed to that Javascript Ajax and displayed. That's easy enough so far.

It gets more complicated when you allow that same page to be passed a URL query param equalling a message id you want specifically to be shown first, instead of just the first row in the query. It's hard to explain but try to follow me. It's not my intention to explain everything like a tutorial so here's the code I implimented to solve my issue.

The page would be called like so, http://www.site.com/showPrivateMessages.cfm?privatemessageid=2435. But remember that the page can be called without the URL param, in which case it would just use the first record in the query of private messages. Including the param would tell the page to display that particular message's details first.

So on the called page I get my private messages query: privateMessagesQuery = event.getValue('privateMessagesQuery'); (I'm using the Coldbox framework)

Set up the param to use with a default of 0: privatemessageid = event.getValue("privatemessageid","0");

Then I need to define which row in the record matches the one I want, but I must set this up first: rowtouse = 0;

Now I need to recurse through the query in a loop to set the rowtouse variable equal to the row found for the id:

<cfif privatemessageid gt 0>
   <cfloop index="i" from="1" to="999999">
      <cfif privateMessagesQuery.privatemessageid[i] eq privatemessageid>
         <cfset rowtouse = i>
         <cfbreak />
      </cfif>
   </cfloop>
</cfif>

Ad now in my Javascript I want to use that row number to set some variables to use in a function call that displays the message details for the message who's id matches that passed in the URL param. I'm not showing the function that does the actual displaying of details, just the function name for time and space's sake (I'm busy).

<$cript>
window.onLoad = loadFirstRequestedMsg(<cfoutput>#rowtouse#</cfoutput>);
function loadFirstRequestedMsg(rowtouse){
   if(rowtouse > 0){
      xPrivatemessageid = "<cfoutput>#privateMessagesQuery.privatemessageid[rowtouse]#</cfoutput>";
      xRead = "<cfoutput>#privateMessagesQuery.readed[rowtouse]#</cfoutput>";
      xSubject = "<cfoutput>#privateMessagesQuery.subject[rowtouse]#</cfoutput>";
      xFrom = "<cfoutput>#privateMessagesQuery.fromUserName[rowtouse]#</cfoutput>";
      xMessage = "<cfoutput>#privateMessagesQuery.message[rowtouse]#</cfoutput>";
      showMessageDetails(xPrivatemessageid,xRead,xSubject,xFrom,xMessage);
   }
}
function showMessageDetails(messageid,read,subject,from,message){
....
}
<InvalidTag>

The showMessageDetails just sets values in span tags, DHTML Ajax stuff. Any ways, you can see here how I'm using ColdFusion inside of Javascript to use back in ColdFusion, or HTML to be technically correct.


Trigger Javascript after loading ColdFusion page

Once apon a time, and still only if I must, I used the 's onLoad attribute to call a Javascript function after a page loaded. I no longer follow that pattern opting instead to use a window DOM method, window.onload, also called a global event handler.

Here is an example of calling a Javascript function on page load in the script block.

<$cript language="javascript">
<!--
window.onload = selectFormField;
function selectFormField(){
   document.paymentForm.x_first_name.focus();
}
-->

</script>
It sets the cursor focus to a selected field in my form on page load.

And I found this cool resource while looking around, it's a book: Structure and Interpretation of Computer Programs or SICP. What does that have to do with this you ask? Well if you need something like the following example of a complexed javascript onload, it might come in handy.

<$cript language="javascript">
<!--
function createMultiDelegate(f1, f2) {
return function() {
if (f1) f1();
if (f2) f2();
}
}
window.onload = makeMultiDelegate(window.onload, aFunction );
-->

</script>

October 16, 2008

Coldbox Framework and Ajax: cfajaxproxy

After working in Coldbox for a while I know your first instinct is to make a cfajaxproxy call to a cfc event just like all the other Coldbox events. However, using cfajaxproxy is just a little different. Here is an example to show you one simple way of doing it, not the only way but one of them.

First let me note that I am using Coldspring version of IOC. It should work the same though with any form of IOC. Mostly we need the IOC to provide the bean to the services your Ajax call requires from within the Coldbox proxy.

After having provided a service in Coldspring like so:

<bean id="usersService" class="model.usersService">
<constructor-arg name="privatemessagesGateway">
<ref bean="privatemessagesGateway"/>
</constructor-arg>
<constructor-arg name="ColdBoxController">
<ref bean="ColdBoxController"/>
</constructor-arg>
</bean>

we can use this "usersService" bean in the coldboxproxy.cfc like this:

<cffunction name="ajxSetPMRead" access="remote" output="false" returntype="void">
      <cfargument name="messageid" type="String" required="true"/>
      <cfset var pm = getBean('usersService').getPrivateMessageByID(int(arguments.messageid))>
      <cfset pm.setRead(1)>
      <cfset getBean('usersService').savePrivateMessage(pm)>
   </cffunction>

The code above is what the Ajax, cfcajaxproxy, will call as a method for Coldbox to perform. It fetches a private message object bean, sets or updates some properties, then uses the gateway to save the object bean. I don't have a return or output but you can do that also here if desired. And here is the actual view and Ajax calling code:

<cfajaxproxy cfc="coldboxproxy" jsclassname="cbProxy">

<a href="##" onClick="showMessageDetails('#privateMessagesQuery.privatemessageid#','#privateMessagesQuery.read#','#privateMessagesQuery.subject#','#privateMessagesQuery.fromUserName#','#privateMessagesQuery.message#')">#privateMessagesQuery.subject#</a>

<$cript>
function showMessageDetails(messageid,read,subject,from,message){
   var e = new cbProxy();
   if(read == 0){
      e.setCallbackHandler(setPrivateMessageRead);
    e.setErrorHandler(ajaxErrorHandler);
    e.ajxSetPMRead(messageid);
   }
   document.getElementById('pmReply').style.display = "none";
   document.getElementById('pmDetails').style.display = "inline";
   document.getElementById('pmDetails_Subject').innerHTML=subject;
   document.getElementById('pmDetails_From').innerHTML=from;
   document.getElementById('pmDetails_Message').innerHTML=message;
}
var setPrivateMessageRead = function(res){
   alert('set to read');
}
var ajaxErrorHandler = function(statusCode, statusMsg){
   alert('Status: ' + statusCode + ', ' + statusMsg);
}
</script>
The cfc attribute is dot notation to the location of your coldboxproxy.cfc, mine here is at the root. Basically I'm showing the private message details in a div but needing to set the read flag in the database to 1 to indicate it has been read. And using Ajax I can set this in the database for each message read without a page refresh. The alerts in the javascript are for demonstration and testing purposes.

The code I provided is a cut down version of actual code and does not include the view event, form code, queries, or other behind the scenes code. I hope this helps to give you a step ahead on how to use Ajax with the Coldbox framework.

July 31, 2007

Hide dynamically generated table rows

Here's one that almost had me coding till midnight until I found a quick simple solution.

If your trying to use javascript DHTML to hide and show multiple generated dynamic table rows with one link/button you may find yourself pulling your hair out. Surrounding the tr's with a div won't work. And giving the tr itself an id and doing it that way won't work because there will be more than one. Then if you try to dynamically name the id's and loop through them; nightmare!!

Tbody to the rescue. I hate tbody's. I never use them and despise when word html includes them. But this is the one time I can think of a good use for it. Surround your dynamically created tr's with one of these, give it an id, and use that to hide and show all the rows at one time.

code example:

script language="javascript" type="text/javascript">
function display(elementid){
   if(document.getElementById(elementid).style.display == "none"){
      document.getElementById(elementid).style.display = "inline";
   }else{
      document.getElementById(elementid).style.display = "none";
   }
}
</script>

<table>
<tr><td>Rows of data: (<a href="#" onclick="display('hidden');">Click to view rows</a>)</td></tr>
   <tbody id="hidden" style="display:none">
      <!---dynamically generated rows of data--->
      <tr><td>row 1</td></tr>
      <tr><td>row 2</td></tr>
      <tr><td>row 3</td></tr>
      <tr><td>row 4</td></tr>
   </tbody>
<tr><td>End of data rows</td></tr>
</table>

July 4, 2007

Input Text Counter

Mostly used for textarea input, with a few changes can be used anywhere you want to count text input. Includes output to a span tag but can be used in a div tag also.

Javascript

function taAntiCount(){
   var taObj=event.srcElement;
   var maxCount=taObj.maxlength;
   if(taObj.value.length==maxCount) return false;
}
function taCount(visCnt) {
   var taObj=event.srcElement;
   var maxCount=taObj.maxlength;
   visCnt.innerText=maxCount-taObj.value.length;
}

HTML

Message(limit <span id="mycounter">500</span> characters)<br/>
<textarea name="message" onKeyDown="return taAntiCount()" onkeyup="taCount(mycounter)" maxlength="255"><textarea>

And yes, I even work on the 4th of July.

June 23, 2007

Vertical Expanding DHTML Javascript Menu

An excellent tutorial on creating vertical expanding DHTML menus I don't want to forget.

http://www.interspire.com/content/articles/10/1/Building-An-Expanding-DHTML-Menu-With-CSS-and-JavaScript

April 20, 2007

Video Tutorials Coming Soon!!!

Creating web based tutorials has traditionally been done using what I call the linear method of tutorial production. This is simply a text and images style of showing how to do something in steps. This way to me is much too time consuming and way too boring. Enter the 21st century..

The technology for screen and audio recording is available, so why not use it, right? Introducing a new tutorial source right here on CFCDeveloper.com. I can get work done and show you some tricks at the same time, how cool would that be!

The "Creating an MVC ColdFusion OOP Application" tutorial I started here in text form will be discontinued in favor for video and audio.

Stay tuned...

November 29, 2006

My First Ajax with ColdFusion

Oh boy! Today I get to add another category to my blog, Ajax. I will share my first go with this fairly "new" technology.

For those of you who might have found this blog looking for Ajax information and your completely new to it, I'll explain Ajax very simply and then move on.

Ajax is not a programming language but uses JavaScript and the browser DOM to do most of the work between client and server. Without JavaScript, there is no Ajax. So it would benefit you to learn JavaScript also if your not already versed. Mostly what Ajax does is ties together web pages with other programming technologies to perform actions on user input "behind-the-scenes". Basically it allows you to get around the whole stateful page-refresh waiting problem.

For instance, with the application I'm about to present, you could make a lookup page where the user enters employee ID's to find employee information from a database. This application could continue to check the database as the user is typing in the ID number and present the result when it hits a valid number.

With my application I'm using ColdFusion on the server end to do the behind-the-scene work. You can possibly translate this to fit your choose of PHP, ASP, JSP, or others. And there are pre-written Ajax frameworks that do it all for you such as Spry and CFAjax, but I like to create my own wheels.

So I'm creating 2 pages, ajaxtest.cfm and getempdata.cfm within the same directory. The user will see and use ajaxtest.cfm which consist of a form to enter an employee ID that also outputs the result when it hits a valid ID you are entering. The ajaxtest.cfm calls to the getempdata.cfm to retrieve results of a query each time the user enters a number. A match will output that employee's data to the form fields.

ajaxtest.cfm

<!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>
<InvalidTag http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Checkout</title>
<style type="text/css">
.invalid {
color:red;
font-weight:bold;
}
.valid {
color:green;
}
</style>
<InvalidTag language="JavaScript" type="text/javascript">
function getXMLHTTPRequest() {
try {
req = new XMLHttpRequest();
} catch (err1) {
   try {
   req = ActiveXObject("Maxm12.XMLHttp");
   } catch (err2) {
      try {
      req = new ActiveXObject("Microsoft.XMLHttp");
      } catch (err3) {
         req = false;
      }
   }
}
return req;
}

var http = getXMLHTTPRequest();

function validateEmployeeID()
{
   if(document.getElementById("employeeid").value == "")
   {
      document.getElementById('feedback').innerHTML = "";
   }
   else
   {
      var target = document.getElementById("employeeid");
   var url = "getempdata.cfm?id=" + encodeURIComponent(target.value);
   http.open("GET", url, true);
      http.onreadystatechange = useHttpResponse;
      http.send(null);
   }
   
}

function useHttpResponse()
{
   if(http.readyState == 4)
   {
      document.getElementById('feedback').innerHTML = '<img src="wait.gif">';
      document.getElementById('fname').value = "";
      document.getElementById('lname').value = "";
      document.getElementById('resultdump').innerHTML = "";
      //alert("State " + http.readyState + " of 4");       if(http.status == 200)
      {
         if(http.responseXML.getElementsByTagName("fname")[0].childNodes[0].nodeValue != "")
         {
            document.getElementById('feedback').className = "valid";
            document.getElementById('feedback').innerHTML = "Found It!!!";
         }
         //alert("HTTP Status Code: " + http.status + " = " + http.statusText);          var fnameValue = http.responseXML.getElementsByTagName("fname")[0].childNodes[0].nodeValue;
         var lnameValue = http.responseXML.getElementsByTagName("lname")[0].childNodes[0].nodeValue;
         document.getElementById('fname').value = fnameValue;
         document.getElementById('lname').value = lnameValue;
         document.getElementById('resultdump').innerHTML = "Using Ajax to call a CFM page which searches the database and returns the result in XML, we created a page not requiring a refresh to lookup data from a database. " + fnameValue + " " + lnameValue + " was found in the database matching that ID.";
      }
   }
   else
   {
      document.getElementById('feedback').innerHTML = '<img src="wait.gif">';
      //alert("State " + http.readyState + " of 4");    }
}
</script>
</head>

<body>
<p>I am using Ajax to retreive employee data.</p>
<p>Enter an employee ID. Try more than one (testing: 263000).</p>
<form id="checkid" name="checkid" method="post" action="ajaxtest.cfm">
<table width="467" border="0" cellspacing="0" cellpadding="3">
<tr>
<td width="108"><strong>Employee ID:</strong> </td>
<td width="150"><input name="employeeid" type="text" id="employeeid" onkeyup="validateEmployeeID()" autocomplete="off" /></td>
<td width="191"><div id="feedback"></div></td>
</tr>
<tr>
<td>First Name: </td>
<td colspan="2"><input name="fname" type="text" id="fname" /></td>
</tr>
   <tr>
<td>Last Name: </td>
<td colspan="2"><input name="lname" type="text" id="lname" /></td>
</tr>
</table>
</form>
<br/>
<table width="100%" border="0" cellspacing="0" cellpadding="3">
<tr>
<td><div id="resultdump" style="width:300px;"></div></td>
</tr>
</table>

<p>&nbsp;</p>
</body>
</html>
I'm not really going to explain this in detail. I'm asuming that my readers pretty much just need some code and they can figure out the rest, just like how I do it.

getempdata.cfm

<cfprocessingdirective suppresswhitespace="Yes">
<cfcontent type="text/xml; charset=utf-16">
<cfxml variable="xmlobject">

<cfif isDefined("form.id")>
   <cfset employeeid = form.id>
<cfelse>
   <cfset employeeid = url.id>
</cfif>

<cfquery name="getEmployeeID" datasource="Sixbits_DB">
select FIRST_NAME, LAST_NAME
from Employees
where EMPLID = <cfqueryparam cfsqltype="cf_sql_varchar" value="#employeeid#">
</cfquery>

<employee>
   <cfoutput query="getEmployeeID">
   <id>#employeeid#</id>
   <fname>#FIRST_NAME#</fname>
   <lname>#LAST_NAME#</lname>
   </cfoutput>
</employee>

</cfxml>
<cfset myvar=toString(xmlobject)>
<cfset mynewvar=replace(myvar, "UTF-8", "utf-16")>
<cfoutput>#mynewvar#</cfoutput>
</cfprocessingdirective>

Some of the code is not needed as I was using it to experiment with. Other stuff you have to change to suit your own environment, such as providing your own database and data. But hopefully you find something that will help you. Later when I get a little better at this I can write a full tutorial with an actual working demo.

October 25, 2006

DHTML Window Popup

A little script to spread the love. A lot of "companies" that make scripts like this, would rather sell it than give it away. But I don't sell anything, yet. So here it is. A Javascript using some DHTML to open a window on click or pageload or whatever. Some think of it as an anti-popup, or an unblockable popup window. I will assume you know a little about Javascript and such and can customize this yourself to fit your exact needs. There are a lot of ways you can change the coding around to do different things.

Place in head in script tag.

var IE = document.all?true:false
if (!IE) document.captureEvents(Event.MOUSEMOVE)
document.onmousemove = getMouseXY;
var tempX = 0
var tempY = 0

function getMouseXY(e) {
if (IE) {
tempX = event.clientX + document.body.scrollLeft
tempY = event.clientY + document.body.scrollTop
} else {
tempX = e.pageX
tempY = e.pageY
}
if (tempX < 0){tempX = 0}
if (tempY < 0){tempY = 0}
return true
}

var dragapproved=false
var minrestore=0
var initialwidth,initialheight
var ie5=document.all&&document.getElementById
var ns6=document.getElementById&&!document.all

function iecompattest(){
return (!window.opera && document.compatMode && document.compatMode!="BackCompat")? document.documentElement : document.body
}

function drag_drop(e){
if (ie5&&dragapproved&&event.button==1){
document.getElementById("dwindow").style.left=tempx+event.clientX-offsetx+"px"
document.getElementById("dwindow").style.top=tempy+event.clientY-offsety+"px"
}
else if (ns6&&dragapproved){
document.getElementById("dwindow").style.left=tempx+e.clientX-offsetx+"px"
document.getElementById("dwindow").style.top=tempy+e.clientY-offsety+"px"
}
}

function initializedrag(e){
offsetx=ie5? event.clientX : e.clientX
offsety=ie5? event.clientY : e.clientY
document.getElementById("dwindowcontent").style.display="none" //extra tempx=parseInt(document.getElementById("dwindow").style.left)
tempy=parseInt(document.getElementById("dwindow").style.top)

dragapproved=true
document.getElementById("dwindow").onmousemove=drag_drop
}

function loadwindow(url,width,height){
if (!ie5&&!ns6)
window.open(url,"","width=width,height=height,scrollbars=1")
else{
document.getElementById("dwindow").style.display=''
document.getElementById("dwindow").style.width=initialwidth=width+"px"
document.getElementById("dwindow").style.height=initialheight=height+"px"
document.getElementById("dwindow").style.left=tempX+"px"
document.getElementById("dwindow").style.top=tempY+"px"
//document.getElementById("dwindow").style.left="30px" //document.getElementById("dwindow").style.top=ns6? window.pageYOffset*1+30+"px" : iecompattest().scrollTop*1+30+"px" document.getElementById("cframe").src=url
}
}

function closeit(){
document.getElementById("dwindow").style.display="none"
}

function stopdrag(){
dragapproved=false;
document.getElementById("dwindow").onmousemove=null;
document.getElementById("dwindowcontent").style.display="" //extra }

Place this just before ending body tag:

<div id="dwindow" style="position:absolute;background-color:#EBEBEB;cursor:hand;left:0px;top:0px;display:none" onMousedown="initializedrag(event)" onMouseup="stopdrag()" onSelectStart="return false">
   <div style="background-color:#5A7D8C; height:18px; padding-top:3px; padding-right:3px; padding-left:13px;">
      <div style="float:left; color:#FFFFFF; font-family:Arial, Helvetica, sans-serif; font-weight:bold;">Title</div>
      <div align="right" style="float:right;">
         <img src="images/close.gif" width="16" height="14" onClick="closeit()">
      </div>
   </div>
   <div id="dwindowcontent" style="height:100%">
      <iframe id="cframe" src="" width=100% height=100%></iframe>
   </div>
</div>

Example of use:

<a href="#" onmouseover="javascript:loadwindow('window_popup.html',189,240)">Click here</a>

And you have to make your own close.gif image.


Copyright © 2005-2006 Clint Willard. All rights reserved.
Aura skin for Clint Willard's BlogCFC inspired by Brooks Bilson's Bolg.
All trademarks property of their owners.