Tuesday, December 1, 2009

listAppend()...Why?

I ran into an annoyance twice this week with the listAppend() in Coldfusion. Below is two ways of storing stuff, an array and a list.



<cfset borders = arrayNew(1)/>

<cfset arrayAppend(borders,"Joe")/>
<cfset arrayAppend(borders,"Jamie")/>
<cfset arrayAppend(borders,"Jake")/>


<cfset borders = ""/>

<cfset borders = listAppend(borders,"Joe")/>
<cfset borders = listAppend(borders,"Jamie")/>
<cfset borders = listAppend(borders,"Jake")/>


I used both ways a ton this week and kept wanting to call listAppend() the same way arrayAppend() is called...but sadly listAppend() doesn't work like that. For some weird reason you need to set boarders (the list var) back to itself because listAppend() doesn't just add it to the variable above just like arrayAppend() does. listAppend() returns you the list with the new append value. Why? I just want to use it like arrayAppend()...it's cleaner and smaller code. Maybe I am missing an important point of listAppend() or don't understand a concept fully, but this is bugging me.

Sunday, November 29, 2009

Break it up

I attended an Adobe MAX session a few weeks ago (The Business Value of User Experience) and I began to relate to some of the struggles that others have had with interfaces and user experiences. Things like how to accommodate multiple types users and guiding users through processes are the major points I picked up from the session.

Handling Multiple User Audiences.
We have all ran into this issue before and if you haven't...you should. How do we handle power users vs. regular users? Power users are the small group of individuals that are going to stretch the app to the boundaries. Regular users are going to do their tasks and are usually just looking to get their "computer work" done asap. So how do we address the power user's needs without confusing or frustrating the regular user's UX? How do we break up complex problems when we code? We break up the code into smaller, more manageable chunks. So we break up the UI when we have complex options or features.

The biggest thing to remember when handling multiple audiences is don't wreck the majority audience's UX. If you need to implement extra options or features in the UI for the power users, separate them from the core options or features. What I am saying is only show what is needed and have a place separate from the main screens, to make the options available for the power users. The power users will find those options, they don't care where the options or features are they just needed the ability to have them. The regular users don't care about the extra options or features and don't even need to know about them. Keep the regular users processes straight forward. Aim for no frustrate or hassle with them. A good example of how to implement this is do what MS did. They implemented an "Advanced" option, usually in the navigation form of a button to hide all the extra options and features. Another word that works well is "Settings".

Guiding the User.
We have all been guided through wizards that we click "Next...Next...Next" all the way through. This is a great way to walk users through a complex problem. But sometimes users don't need a multi-screen wizard to walk them through a process. Sometimes they just need some clarity or steps to verify against as they complete a screen. A good way to do this is by displaying a vertical wizard. A vertical wizard doesn't have to be a complex process that the user is being walked through. It can simply provide clarity to know that what they are filling out is used for something. A good example of this is Campaign Monitor's sign up wizard.

A last random note is to remember that your users are people. Remember that people hate making decisions, but always want the decisions available.

Thursday, September 24, 2009

The cowering developer.

I wanted to talk a little bit about ownership and the frustrations I have with developers who don't own up their work. We all do it, just in varying degrees.

Have you ever noticed that some developers never own up to there work? A developer added some logic that made if confusing for you to follow, but they won't own up to their work. Trying to get anything out of them is like talking to a wall. I wonder what they're afraid of. I've put up with this for too long and need to talk about it.

Some developers feel it's "ok" to NOT take ownership or responsibility of their work. I think they are afraid of confrontation. If I want to know who did something, I am not looking to target someone and humiliate them. I am trying to solve an issue with which I am having trouble following their trail. I feel that the developer thinks that if they speak up that they will have to fix something or possibly "do more work". Yes, there are some immature developer that do make you fix it and will call you out in front to make themselves feel smarter, but I feel that most are just trying to solve an issue for which they need an assist with.

These "cowering" developers create more frustration, waste time and resources, and push the work off on other developers. I am sick of watching irresponsible developers go home to their friends and family while other developers clean up the messes. I am sure there is some angry significant others out there whom have a few words to say. I am sick of having long arguments in the same area of the developer who wrote the piece but they are just sitting there and listening and don't have the courage to stand up and assist.

Yes I know there are cases where we had to throw some not so good code in because of some crazy business logic, but it doesn't mean you are stuck with that piece forever. Others will come behind, follow your trail, and try to tweak/fix your piece. They may need help or point them in the right direction. If you choose to "cower" in the corner, it will be noticed and remembered. Swallow some pride and own up to the code.

Sunday, September 20, 2009

PHP and checkboxes with the same name

If you have worked with ColdFusion before you know that if have checkboxes in the form that have the same name they come into the form scope as a comma separated list. I tried to pull the same trick using PHP but only go the last checkbox's value. Confused I did a little a research and found out that if you put [] behind your name PHP interprets it as an array but keeps everything to the left of the [] as your name when comeing in through the $_REQUEST scope. See below.

<form name="the_form" method="post">

<input type="checkbox" name="boarder" value="Joe" >
<input type="checkbox" name="boarder" value="Jamie" >
<input type="checkbox" name="boarder" value="Jake" >

</form>

In ColdFusion when you submit this form you would get an variable in the form scope
called "boarder" with the values "Joe,Jamie,Jake" in a comma seperated list. In PHP you would get "Jake". To solve this I added [] to the checkbox name.

<form name="the_form" method="post">

<input type="checkbox" name="boarder[]" value="Joe" >
<input type="checkbox" name="boarder[]" value="Jamie" >
<input type="checkbox" name="boarder[]" value="Jake" >

</form>

Now in PHP you would get an variable in the $_REQUEST scope called "boarder" which is type array with first element "Joe, the second element "Jamie", and the third element "Jake". Notice the variable name is still "boarder" even though we specified "boarder[]".

I am not choosing sides on PHP or ColdFusion they are both cool, but I found it interesting that you can tell PHP what type this var is through the html form.

I found my answer at:
http://www.computing.net/answers/webdevel/php-amp-checkboxes/1122.html#postfp

Monday, September 7, 2009

Adding a node to an existing xml object

So I struggled with an interesting task the other day, that should have been easy. I had an xml object with which I was to add additional node too. Sounds simple right. The part I struggled with was the ColdFusion function "xmlElemNew()". I kept wanting to put in that third optional argument. Enough blabbing, here's how I did it.

Here is my xml file or xml object.


<boarders>
<boarder>
<name>Joe</name>
<board>Forum</board>
<gender>M</gender>
</boarder>
</boarders>


I want to add another boarder.

Here I am reading from a file but the same thing works for an xml object.


<cfset xml = xmlParse("boarders.xml")/>


I create my new boarder node, using the variable xml as my "xml document".

<cfset boarder = XmlElemNew(xml,"boarder")/>


Next I create some extra nodes "name,gender, and board" and append it to the boarder node using arrayAppend(). Each time I make the "extra nodes" I set the value of the node by using XmlText, which is an attribute of xml object in ColdFusion. Finally we add the node the children of the boarder node created earlier.

<!---name--->
<cfset name = XmlElemNew(xml,"name")/>
<cfset name.XmlText = "Jamie"/>
<cfset arrayAppend(boarder.XmlChildren,name)/>

<!---gender--->
<cfset gender = xmlElemNew(xml,"gender")/>
<cfset gender.XmlText = "F"/>
<cfset arrayAppend(boarder.XmlChildren,gender)/>

<!---board--->
<cfset board = xmlElemNew(xml,"board")/>
<cfset board.XmlText = "Nitro"/>
<cfset arrayAppend(boarder.XmlChildren,board)/>

Once we are ready to add the node the xml object we just arrayAppend() just like we did with the above nodes "name,gender,and board".

<cfset arrayAppend(xml.boarders.XmlChildren,boarder)>

<cfdump var="#xml#">

<cfabort/>



That's it.

To recap quick:
1. Create the node using XmlElemNew().
2. Set the node value using XmlText().(optional)
3. Append the node to the parent node using arrayAppend().

Took me forever to figure it out. Sad I know.

Wednesday, September 2, 2009

PDF's 101

I wanted to share my first experience with pdf's and how simple ColdFusion makes working with. Previously, when I had to do something with a PDF it was changing some styles on a .cfm that's content was wrapped in cfdocument tags, so I didn't really learn much. I got put on a project that had us generate pdfs and learned a lot from the experience. When I first started working on the project I was nervous because I didn't know XML or XSLT, but quickly realized they are not hard at all. Here is a small example of my process for creating a pdf. My goal was no files, which means I save the pdf in the database, but in this example I will show where you can either create a file or save it to the database.

First we have some data that we want to display on a PDF. I like snowboarding so I made an array of structs with data regarding each boarder. Mostly we would have a whole bunch of queries who's data we would to display but I just want to keep it simple.

<cfset boarders = arrayNew(1)/>

<cfset boarder = structNew()/>
<cfset boarder.id = 1/>
<cfset boarder.name = "Joe"/>
<cfset boarder.board = "Forum"/>
<cfset boarder.gender = "M"/>
<cfset arrayAppend(boarders,boarder)/>

<cfset boarder = structNew()/>
<cfset boarder.id = 2/>
<cfset boarder.name = "Ben"/>
<cfset boarder.board = "Burton"/>
<cfset boarder.gender = "M"/>
<cfset arrayAppend(boarders,boarder)/>

<cfset boarder = structNew()/>
<cfset boarder.id = 3/>
<cfset boarder.name = "Jake"/>
<cfset boarder.board = "Santa Cruz"/>
<cfset boarder.gender = "M"/>
<cfset arrayAppend(boarders,boarder)/>

<cfset boarder = structNew()/>
<cfset boarder.id = 4/>
<cfset boarder.name = "Jamie"/>
<cfset boarder.board = "Nitro"/>
<cfset boarder.gender = "F"/>
<cfset arrayAppend(boarders,boarder)/>

<!---dump the data--->
<cfdump var="#boarders#" label="boarders"/>

After we have our data we need make some xml. If you haven't work with xml, think of it like html, but you can make your own tag names. Here I create a node called "boarder" which I store properties about the boarder like name, board, and gender. The xml will act as our data when working with the pdf. Later the xslt will be our styles for the pdf.

<cfset xml = arrayNew(1)/>

<cfloop from="1" to="#arrayLen(boarders)#" index="i">

<cfsavecontent variable="boarder">
<cfoutput>

<boarder>
<id>#boarders[i].id#</id>
<name>#boarders[i].name#</name>
<board>#boarders[i].board#</board>
<gender>#boarders[i].gender#</gender>
</boarder>

</cfoutput>
</cfsavecontent>

<cfset arrayAppend(xml,boarder)/>

</cfloop>

<!---dump the xml--->
<cfloop from="1" to="#arrayLen(xml)#" index="i">
<cfdump var="#xmlParse(xml[i])#" label="#i#">
</cfloop>

After we have the data the next piece is to create some xslt. Remember xslt is the styles of the xml. If you haven't worked with xslt, the basic idea is you loop through your xml nodes "the custom tags you made" and output the data. You loop through a node by doing <xsl:for-each select="boarder">. If you want the value of node you do this <xsl:value-of select="name"/>. This should get you by, you will have to search W3schools for the rest.

<cfsavecontent variable="xslt">
<cfoutput>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
<html>
<body>
<xsl:for-each select="boarder">

<table border="1">

<tr>
<td>Name:</td>
<td><xsl:value-of select="name"/></td>
</tr>

<tr>
<td>Gender:</td>
<td><xsl:value-of select="gender"/></td>
</tr>

<tr>
<td>Board:</td>
<td><xsl:value-of select="board"/></td>
</tr>

</table>

</xsl:for-each>
</body>
</html>
</xsl:template>

</xsl:stylesheet>

</cfoutput>
</cfsavecontent>

<---dump the xslt--->
<cfdump var="#xslt#">


The next piece is where we actually merge the xml and xslt together to create html. Once we have the html we can run it through cfdocument tags and get it in pdf format.

I start an array to hold the info regarding each document.

<cfset documents = arrayNew(1)/>

<cfloop from="1" to="#arrayLen(xml)#" index="i">

<cfset document = structNew()/>


I get the xml which we create earlier.

<cfset document.xml = xml[i]/>

I get the xslt which we create earlier.

<cfset document.xslt = xslt/>

I merge the xml and xslt together using xmlTransform(), a built in ColdFusion function and it will return my html.

<cfset document.html = xmlTransform(xml[i],document.xslt)/>

I wrap my html in cfdocument tags with a format of pdf. This will return me a binary object of the pdf. Earlier I mentioned about creating a file or saving it to the database...this is that point.

<cfdocument name="document.binary" format="pdf">
<cfoutput>#document.html#</cfoutput>
</cfdocument>

Since I didn't want to create any files I convert the binary object to base64 so I can save it in my MSSQL database. I can always pull the base64 from the databased and use toBinary() to convert it back to a binary object.

<cfset document.base64 = toBase64(document.binary)/>

<cfset arrayAppend(documents,document)/>

</cfloop>

<!---dump the documents array--->
<cfdump var="#documents#" label="documents">


At this point you can be done or if you want, since we have the all the pdfs in the array called documents, we can loop through them and merge them into one pdf so we can print 1 document instead of each document individually.

Pretty basic here. The only thing crazy is I loop through the documents again an apply them as source to the main pdf, named "final", I want to merge. The pointer is important because you can't directly throw the variable into the pdfparam source attribute...it requires a variable name, this took me along time to figure out.

<!--- merge documents --->
<cfpdf action="merge" name="final">

<cfloop from="1" to="#arrayLen(documents)#" index="i">
<cfset pointer = documents[i].binary/>

<cfpdfparam source="pointer"/>
</cfloop>

</cfpdf>

That's it, all the documents we created early are all merged into 1 single pdf, we can print them once. Now we just can the content tag to display the pdf to the browser.


<cfcontent type="application/pdf" variable="#toBinary(final)#" reset="no" />

Pretty harmless huh.

Tuesday, August 25, 2009

Connecting Coldfusion to a Java class.

For a while now I've want to know how to call Java from ColdFusion but didn't know how. After waking up any Java memories I had from making my "hello world" I found out it was really easy to do.

1. user.java
Remember Java is case sensitive unlike ColdFusion.

public class user{
public String getName(){

String name = "joe";
return name;
}
}

2. Drop the user.java file C:\JRun4\servers\cfusion\cfusion-ear\cfusion-war\WEB-INF\classes directory.
--NOTE I am using localhost mulitserver and this is where I put it.

3. Test.cfm
I create a test.cfm and create an object of user. I can now work with the object.

<cfset user = createObject("java", "user")>
<cfdump var="#user#">

<cfset name = user.getName()/>
<cfdump var="#name#">

Monday, August 10, 2009

PHP and singleton's

So I wanted to have use singletons in php, but couldn't find any good tuts that didn't involve cake or zend. I did quite a bit research and asking around and here is what I came up with. I framed the findings around Coldspring which is a ColdFusion dependency injection tool, which basically means it handles your objects for you.

First I have an xml file where I define where my objects (classes) are. If you are not familiar with MVC, I would first suggest reading up on it. But anyways, below I define some objects paths so I don't have to worry about where they are. As you can see I have an objects controller, service, and gateway.

<?xml version="1.0" encoding="ISO-8859-1"?>
<objects>

<object name="objectsController" type="controller" address="app/controllers/objectsController.php"/>
<object name="objectsService" type="service" address="app/services/objectsService.php"/>
<object name="objectsGateway" type="model" address="app/models/objects/objectsGateway.php"/>

</objects>

The next step is to read in the xml nodes. So below is a function that I feed a path to my xml file (above) and it returns me the nodes in PHP.

public function loadSimpleXML($xmlPath){
if (file_exists($xmlPath)) {
$xml = simplexml_load_file($xmlPath);
return $xml;
}else{
exit('Failed to open '.$xmlPath);
}
}

The next step I loop the nodes with the name "object" and do stuff with it.

//create singletons array to hold objects in
$singletons = array();

//get the count of the nodes
$cnt = count($xml->object);

//loop object nodes
for($i = 0; $i < $cnt; $i++) { $object = $xml->object[$i];

//get object name and address
$name = $this->getAttribute($object,"name");
$address = $this->getAttribute($object,"address");

//include the file
$this->loadClass($address);

//create an instances of the object
$pointer = (string)$name[0];
$singletons[$pointer] = new $pointer;

}

Alot of stuff happened in the above function so I will break it down by a few lines. First we get the node by doing:

$object = $xml->object[$i];

After we get the node I call a function to get the attributes of the node. In my case I just want the name and where the object file is at.

$name = $this->getAttribute($object,"name");
$address = $this->getAttribute($object,"address");

public function getAttribute($node,$name){
$attrs = $node->attributes();

return $attrs[$name];
}

Next I have to include the file. In PHP I found out you need to include the file if you want to use it. To do this I created a function that does a require_once(). I know you don't need a function for it but I figure it didn't hurt and this way if I have to do anything before my include or after I have the ability to do it now. In case you don't $this is used to call a function within a object file. Also you notice I have a variable call $GLOBALS["siteroot"]. I actually load up an environment xml file that takes of these properties but to be straight...the variable just contains the site root of my project, so no biggie here.

$this->loadClass($address);

public function loadClass($classPath){
require_once($GLOBALS["siteroot"].$classPath);
}

The next part was the hard part...dynamically creating an instance of the object. I found out that I needed to use a pointer to use "new", which took forever to figure out, because me and pointers don't mix (I just wanna chain stuff together). Anyways here's what I got.

//create an instances of the object
$pointer = (string)$name[0];

//append object to an array objects so they can be used later.
$singletons[$pointer] = new $pointer;

Later I store the $singleton's array in the $GLOBAL scope because it's the only scope that I know is some what persistant...but it's not. I don't think PHP has a persistant scope without creating a session. If any one has any ideas on where I can put this $singletons array so I don't to have read it from the xml everytime (if you caught the globals...I am techinically not fully using the singleton's pattern because I have no scope to put it in) I would greatly appreciate it, but I have found this works pretty slick for now.

Sunday, August 9, 2009

Robot Coders

In most trades people do what they are told, it gets done, and life goes on. Development requires you think into the future to prevent issues, which may bring a developer to challenging the validity of the task. Challenging a task could potentially bring up new ideas or issues. I am not saying challenge every thing that is assign to you, but do a quick check against the current state of the app. A quick check could create a new module or even a product. It could also bring up trickle down issues that may occur from bringing in a new change or feature.

From what I've seen so far,in the 2 years of coding, is that some developers are mindless coders. They are like robots whom take input and return results. While management loves this, development hates it. The problem with coding this way is you get crap code that only serves a one-off purpose from either a quick decision or sales promise and harms the purpose of a feature or even the app. I just think things should be thought through a little more before they are coded up, and it is the responsibility of the coder , as a last resort, to take care of this. I am not asking for a design meeting, but 5 to 10 minutes of quick thinking or maybe a peer's opinion may bring something important up that will save time and money in the long run.

A few things I do before coding something up are:
1. What parts will be affected?
2. Will this change the current purpose of the code in a way that is not desired or maybe interpreted incorrectly?
3. How much code do I need to change?
4. Do the database relationships support what I am going to do?
5. Do I have the time to make the changes without throwing some spaghetti code together?
6. Will my changes effect/prevent someone else's ability to work?
7. Do I need a hand with the design or amount of this task?
8. Are the changes worth my time right now or are there bigger fish to fry first?

These are just a few things that go through my mind before I begin a task. I think the robot coders should become human again, by learning to think outside the box or for themselves and not by an outside entity. What goes though your guy's mind before you begin coding?

Monday, June 15, 2009

Select into from ColdFusion query object

So I got a question from a friend of mine who had a query returned in ColdFusion and wanted to do a "select into" with the query object. He found out how to do it one statement. Check it out.


<cfquery datasouce="ds">
SELECT COLUMN_1,COLUMN_2,COLUMN_3
INTO DATABASE_TABLE
FROM QUERYOBJECT.THEQUERY
</cfquery>

Thursday, May 21, 2009

Default on bit column in sql.

alter table tablename
add constraint DF_tablename_columnname default ((0)) for columnname

Monday, May 18, 2009

Merging cfdocuments into pdf without creating a file

So I was working with a dms and wanted to try not writing and reading pdf files but instead using the cf and db to display the data. I struggled with invoking cfpdfparam source attribute on cfpdf action="merge" because it doesn't take straight up binary, which is what cfdocument is returning. So I created a pointer variable and passed that in and it accepted. Kinda wierd it wouldn't accept it but oh well. Check it out.


<!--- get the pages --->
<cfset pages = beans.docService.getPagesByVersionID(versionID=versionID)/>

<!--- create array to hold cfdocuments --->
<cfset documents = []/>

<!--- loop pages and create cfdocuments --->
<cfloop query="pages">

<cfdocument name="pdf_name" format="pdf" pageheight="#pages.height#" pagewidth="#pages.width#" pagetype="#pages.doc_page_type_Name#" orientation="pages.document_orientation_type_name#">

<!--- get the page layout --->
<cfset layout[id] = beans.docService.getLayoutByID(pages.layout_id) />

<!--- get xmltransform--->
<cfsilent>
<cfset html[id] = xmltransform(xml,layout[id].xslt) />
</cfsilent>

<!--- set margins --->
<cfdocumentsection
marginbottom="#pages.bottom_margin#"
marginleft="#pages.left_margin#"
marginright="#pages.right_margin#"
margintop="#pages.top_margin#">

<!--- output data --->
<cfoutput>#html[id]#</cfoutput>

</cfdocumentsection>

</cfdocument>

<!--- add binary cfdocument to the --->
<cfset arrayappend(documents,pdf_name) />

</cfloop>


<!--- merge cfdocuments into 1 pdf. this will return some binary --->
<cfpdf action="merge" name="final">

<cfloop from="1" to="#arraylen(documents)#" index="i">

<!--- set pointer for cfpdfparam source, this part took me forever to figure out because the source attribute is looking for a pointer variable. you can't just pass in the binary --->
<cfset pointer = documents[i]/>

<cfpdfparam source="pointer">

</cfloop>

</cfpdf>

<!--- output the pdf --->
<cfcontent type="application/pdf" variable="#tobinary(final)#" reset="No" >

Wednesday, May 13, 2009

The litte things

As I logged into my bank accounts online I realized how much of the little things are missing from a page. Details such as label tags on radio and checkboxes, titles on links, and directions steps in a wizard are just to name a few. When working with presentation, people remember every little detail. So remember to think of the little things.

Wednesday, April 22, 2009

Coldfusion writing simple xslt

I think it would be kinda cool to not have to write xslt as much any more, so a coworker and I created some helper functions to handle tables for us. So instead of writing xslt to create a table tag where we can pump xml into we created coldfusion functions with which can shoot args and write the xslt for us.

Here we call a beginTable() with which we can give it attributes.

<cffunction name="beginTable" access="public" returntype="string" output="false" >

<cfset var local = {} />

<cfset arguments = getArguments(arguments) />

<cfsavecontent variable="local.string">
<cfoutput>
<xsl:call-template name="beginTable">

#renderXSLTParams(argumentCollection=arguments)#

</xsl:call-template>
</cfoutput>
</cfsavecontent>

<cfreturn local.string>

</cffunction>

First we can getArguments which handles our common attributes of the tag we are trying to create. getArguments() can be used to set out defaults but of simplicity we just loop a list of common attributes.

<cffunction name="getArguments" access="public" output="false" returntype="struct">
<cfargument name="args" required="true" />

<cfset var local = {} />

<cfset local.args = arguments.args />

<cfloop list="class,style,title,alt,id,height,width,colspan,cellspacing,cellpadding,align,border,src,value" index="local.i">
<cfset local.args[lcase(local.i)] = getKey(lcase(local.i),local.args,"#local.i#") />
</cfloop>

<cfreturn local.args />

</cffunction>

Second, we write the xlst beginTable template and create the xslt params using renderXSLTParams.

<cffunction name="renderXSLTParams" access="public" returntype="string" output="false" >

<cfset var local = {} />
<cfset var i = "" />

<cfsavecontent variable="local.string">
<cfoutput>
<cfloop collection="#arguments#" item="i">
<xsl:with-param name="#lcase(i)#">
<cfif (FindNoCase('%',arguments[i],1) or FindNoCase('px',arguments[i],1) )>
<xsl:text>#arguments[i]#
<cfelse>
<xsl:value-of select="#lcase(arguments[i])#"/>
</cfif>
</xsl:with-param>
</cfloop>
</cfoutput>
</cfsavecontent>

<cfreturn local.string/>

</cffunction>

That takes care of creating the xslt snippet for the begin table tag, now we have to load the tag at the bottom of the xslt so we can call the template and invoke the params. To do this we output the load function which contains all our template snippets.

<cffunction name="load" access="public" output="false" returntype="string" >

<cfset var local = {}/>

<cfsavecontent variable="local.string">
<cfoutput>
<xsl:template name="beginTable">
#getTemplateParams()#
<xsl:text disable-output-escaping="yes"><</xsl:text>table
#getXSLTParams()#
<xsl:text disable-output-escaping="yes">></xsl:text>
</xsl:template>

<xsl:template name="endTable">
<xsl:text disable-output-escaping="yes"><</xsl:text>/table
</xsl:template>

</cfoutput>
</cfsavecontent>

<cfreturn local.string/>

</cffunction>

In the load function we call getTemplateParams() to create our template params.


<cffunction name="getTemplateParams" access="public" returntype="string" output="false" >

<cfset var local = {}/>
<cfset var i = ""/>

<cfset arguments = getArguments(arguments)/>

<cfsavecontent variable="local.string">
<cfoutput>

<cfloop collection="#arguments#" item="i">

<xsl:param name="#lcase(i)#"/>

</cfloop>

</cfoutput>

</cfsavecontent>

<cfreturn local.string/>

</cffunction>

Next we call getXSLTParams(). to actually invoke the xslt params

<cffunction name="getXSLTParams" access="public" returntype="string" output="false" >

<cfset var local = {}/>
<cfset var i = ""/>

<cfset arguments = getArguments(arguments)/>

<cfsavecontent variable="local.string">
<cfoutput>

<cfloop collection="#arguments#" item="i">
<xsl:if test="$#lcase(i)# != '' ">
#lcase(i)# ='
</xsl:if>
</cfloop>

</cfoutput>
</cfsavecontent>

<cfreturn local.string/>

</cffunction>

And that should do it.

Thursday, April 9, 2009

Accessing a queries row by row number

query.column[rownumber]

I was asked to do a task which involved a select box with arrows on each side of it. The arrows were to be used for the next and previous record in the select box when the page first rendered. For awhile I have wanted to use a query row number to access data directly and now get the chance to.

I used the current selected id and loop the query just got the above and below row from the current row by accessing the query struct.

Example:


<cfset the_id="124"/>
<cfset above_id=""/>
<cfset below_id=""/>

<cfloop query="the_query">

<cfif the_id = the_query.id>

<cfset above_id= the_query.id[currentrow + 1] />

<cfset below_id= the_query.id[currentrow - 1] />
<cfbreak />
</cfif>
</cfloop>

Monday, March 23, 2009

javascript for each loop

I ran into an issue today with the javascript for each loop. The for each loop would run one extra time and return the value "each" for the variable "field" in example below.

Example 1
for(var field in array){
//some code
}

To solve this I switched up the for each loop to do it this way instead.

Example 2
array.each(function(field){
//some code
});

Not sure what the difference is between Example 1 and Example 2.

Thursday, March 19, 2009

cfqueryparam cf_sql_decimal scale default

A few months ago I was debugging some code that was rounding to the nearest int even though the data being entered was of decimal type. I checked the code to see if round() or numberformat() was being used, but they weren't. I started throwing dumps in the cfquery and noticed that before the decimal var entered in the cfqueryparam it was a decimal, but when the query was ran it was of type int. I was totally confused on how the number was being formatted. Turns out there is a scale attribute I was unaware of on cfqueryparam. The scale attribute is defaulted to 0 and is only applicable to cf_sql_numeric and cf_sql_decimal. I think it's kinda pointless for cf_sql_decimal to have zero decimals. Anyways I ended up adding scale to cfqueryparam with a value of 2 and fixed the issue.

I can see why scale of zero would make sense for cf_sql_numeric but not for cf_sql_decimal.

Monday, March 16, 2009

ColdFusion and PDF font-size pt vs px

So a few months ago I was walking by a developers desk and stopped when I saw him frustrated with some ColdFusion PDF output. He was working with font size's in using pixels (Ex. font-size:15px;) and it was not rendering the same in FireFox and IE. I sat down with him for a bit and we both thought using pixels instead of points (Ex. font-size:15pt) would be compatible across browsers. Our idea was wrong. I went back to my desk and played around with the compatibility of different pixel sizes in the two browsers but had no luck. Giving up with the pixel's idea, I then tried pt. Using pt worked far better then px when dealing with PDF.

Air Boards / Hover Boards

So I was driving to a ski resort to snowboard with my girlfriend and it was 50 degrees. My thoughts as I drove with the A/C blasting, were "I am going to loose 10 pounds in sweet today" and "What were thinking? It's way to warm to be doing this". As I rolled down the window to let some fresh air in, I started thinking about the movie Back to the Future and those crazy cool air boards they had in the movie. We arrived at the ski resort and went snowboarding, threw some snowballs at each other and sweated are butts off. We ended up going home early, so I hopped on Google to do a little research on air boards.

I found a website on how to create an airboard http://www.wikihow.com/Create-a-Hoverboard . It's sounds super easy, reasonably inexpensive (criagslist) to do. Here's a calculator that I found super handy to calculate dims,lift,and power http://www.rqriley.com/hc-calc.html.