Saturday, August 29, 2009

Getting cffile to work in a cfwindow

Figured out how to do a file upload in a cfwindow using cfform. If you try to receive a file upload in a cfwindow, regardless of the enctype specified in the cfform it will incorrectly receive the form as of type "application/x-www-form-urlencoded", instead of the more-better "multipart/form-data. My guess is that this has something to do with the ajax used to submit the form. This error happens even if the originating form is in the cfwindow.

Easy work around? Embed an iframe in the cfwindow, put your form in the iframe, and have the form submit within the iframe using a simple submit button (rather than using ColdFusion.navigate). If you submit the form using a submit button in an iframe, the form's enctype will submit properly, and ColdFusion will correctly receive your file and pass it onto cffile.

This technique will also work with putting a cfpresentation tag in a cfwindow.

Wednesday, September 24, 2008

*Update to previous post* CF-Ajax gets jealous

This post modifies the following previous post:

Create Spry Data Sets Using Inline Data

It turns out that the above doesn't work inside of a bound CFDiv. For instance, if your Spry dataset lives on a pages called data.cfm, and you include data.cfm on another page using a bound cfdiv, it breaks. For the below example, you can put the guts of my previous post on this subject (referenced above) into data.cfm if you want. See the example below:

<----------- data.cfm ----------->
...
Create a spry dataset
...
Show dataset in a dynamic region
...
<----------- End data.cfm ----------->


<----------- view_data.cfm ----------->
...
<cfdiv bind="url:data.cfm" />
...
<----------- End view_data.cfm ----------->


I have spent almost two entire days trying to get the above to work. Interestingly, my research into the above with FireBug shows that I can get it to actually create and populate the dataset. However, try as I might, I can't get the dynamic region in view_data.cfm to show any data. I have researched on the web, and found others with the same finding; for example:

Spry + CFDIV = No Love

I love the CF Ajax goodness, but this is very frustrating and a major limitation. It makes it so that I can't use Spry (and possibly other Ajax frameworks) on big apps that include CF-Ajax (especially bound cfdivs). I work for a government agency, and we write some very large, powerful, complicated apps using ColdFusion. If the CF-Ajax makes it so that I can't extend the CF goodness with other Ajax frameworks, then this is a problem

I am hopeful that Adobe will address these sorts of CF-Ajax quirks in CF 9. If they don't, I will probably think twice in the future about using the CF Ajax features in the future.

Tuesday, September 23, 2008

Create Spry Data Sets Using Inline Data

I finally figured out how to create a Spry dataset using inline data. This is a major step towards usability, and wasn't posted on any of the Spry examples that I searched thru on Adobe's site.

To create a Spry dataset using inline data, you can just create a javascript array, and give the array to the dataset object using the Data Set's setDataFromArray(array) function. I have tested it in both FireFox and IE. You can find more information about the setDataFromArray(array) fuction here: http://labs.adobe.com/technologies/spry/articles/data_api/apis/dataset.html#setdatafromarray

The example below uses ColdFusion syntax to get data from the database and to populate the array. However, this would work with whichever language you like, or even with static data. See the following example:

Example:

<cfquery name="get_users" datasource="ds">
SELECT last_name, first_name, phone, address
FROM user

</cfquery>

<script type="text/javascript" src="Spry_1_6_1_022408/includes/SpryData.js"></script>

<script>

user_array = [<cfloop query="get_users">{last_name: "#get_users.last_name#", first_name: "#get_users.first_name#", phone: "#get_users.phone#", address:"#get_users.address#"}<cfif currentrow="" neq recordcount="">, </cfif></cfloop>]

user_dataset = new Spry.Data.DataSet();

user_dataset.setDataFromArray(user_array);
</script>

<div id="users_region" spry:region="user_dataset">

<table border="1">
<tr>
<th spry:sort="last_name">Name</th>
<th spry:sort="phone">phone</th>
<th spry:sort="address">Address</th>
</tr>
<tr spry:repeat="personnel_dataset">
<td>{last_name}, {first_name}</td>
<td>{phone}</td>
<td>{address}</td>
</tr>
</table>

</div>

You may have noticed that the above example doesn't var scope its JavaScript variables. This was on purpose, and it will still work. Experience has shown that var scoping variables can make them incompatible with some of the ColdFusion 8 CF-ajax stuff.

Thursday, May 01, 2008

ColdFusion Ajax Functions

Tired of looking up the syntax for the ColdFusion 8.0 Ajax functions? Me too. So, I created the following. You can thank me later.

https://acrobat.com/#d=0xInJpmQt0NgwOGzthNHuQ

Monday, April 07, 2008

More JavaScript, More "duh"

Another JavaScript "duh" moment. (You can see my previous JavaScript "duh" moment from last week here: http://nm1m.blogspot.com/2008/04/javascript-duh-moment.html ). A lot of times I want links to fire off JavaScript events, but to still look / taste / feel like links. Previously I have done it like this:

<a href="#" onClick="ColdFusion.Window.create('etc', 'etc.cfm');">
The upshot to this technique is that you get a link that looks and acts like a link. The minus is that when you click it, it appends a hash mark (#) to the end of your url. Not a big deal, but still.

On Friday, at the fabulous Salt Lake RIA Dev Shed, I learned another little "duh" JavaScript technique. Rather than trying to explain it, I will just show. You can do the same thing as the above like this:

<a href="javascript:ColdFusion.Window.create('etc', 'etc.cfm';">

Huzzah for cheap little JavaScript tricks!

Thursday, March 27, 2008

CFEclipse Newbie questions answered

David McGuigan, member of the Salt Lake ColdFusion User Group has posted a useful list of CFEclipse newbie tips. If you use CFEclipse, you might find this list helpful.

You can find it here: http://www.slcfug.org/fusetalk/messageview.cfm?catid=5&threadid=639

Monday, March 03, 2008

Coldfusion Application Server service terminated with service-specific error 2

Sometime last week, one of our main ColdFusion servers needed a bit of a pick-me-up, and one of our server guys juiced it with 2 more gigs of RAM. After the new RAM was installed, I went into the ColdFusion administrator, and upped the MAX Heap Size. I changed it from 1024 to 2048 and saved. It gave me a polite message stating that the change would take effect after the ColdFusion server restarted. I moved on with life, not restarting the server or service at that time; the work day had begun, people were already hitting our server, best to leave well-enough alone.

This morning I checked the cool new ColdFusion Server Monitor included with CF8. I saw several hung threads, which are a sure sign that your server is inching towards becoming unresponsive (the more hung threads, the fewer resources available to working threads). I decided that rather than waiting for our server to stall in the afternoon, I would restart the ColdFusion service right then, and the hung threads would evaporate. So I did. And the service never restarted.

Our main server guy was out of town, and the other server guys were busy, so I dug in to try to figure out what was going wrong myself. I did some research.

In the Event Viewer, I found an error that looked something like this:

"Coldfusion Application Server service terminated with service-specific error 2"
A bit of time on Google taught me that one of the causes of this error is services starting too slowly. This can be mitigated by giving them more generous timeouts. For more information, see the below:

http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_18799

I did what it said there (adjusting for ColdFusion 8), restarted the server, and nothing changed. The ColdFusion service still didn't come up. By now I started to suspect that my JVM Heap changes of the previous week had precipitated the problem. Some more time spent with Google, and I found this useful link:

http://www.coldfusionmuse.com/index.cfm/2005/10/28/jvm.gc

This little gem teaches you how to go into the server's jvm.config and adjust JVM args directly, including the Max and Min Heap sizes. Server restart, and problem solved.

Tuesday, January 15, 2008

Getting dates to appear correctly in an HTML cfgrid

A little while ago, I posted this to my blog, however I didn't give much context, I just dumped a pair of links to fairly dense articles. What do these links tell you? They tell you how to have SQL Server format things for you (in this case dates), similar to using the dateFormat function in ColdFusion. This can come in very handy when working with cfgrids.

Although the Adobe livedocs say that you can mask / format values that go into a grid, I haven't had much success with getting it to work; especially in the case of HTML grids.

A great work-around is just to use the SQL Server CONVERT function. How? If you plug a date/time/timestamp column name into CONVERT, and tell it what you want to convert it to, it will change the data-type of the date/time column (just in the resulting recordset, not in the actual table) to the data-type of your choice, and format the date for you to one of many predefined formats. Lots of examples of this and other techniques here:

http://www.oreilly.com/news/sqlnut_1200.html

For a list of predefined formats, and some more (not very useful) examples, look here:

http://msdn2.microsoft.com/en-us/library/ms187928.aspx

So, if you need to use a date/time column in a cfgrid, just preformat it in the actual query like so:

SELECT CONVERT(VARCHAR(11), date_column, 102) AS formatted_date
FROM table
...etc.

I hope that makes more sense.

Wednesday, January 09, 2008

Binding to an HTML cfgrid

Wanna bind to an HTML cfgrid, and having trouble finding the correct syntax? Here it is:

bind="{gridName.columnName}"

I searched for a couple of hours, and could only find the flash forms syntax. Then I found it documented here:

http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=ajaxui_5.html#1137151


Here is an example using cfinput to bind to the cfgrid :

<cfgrid name="user_grid" query="get_users">
<cfgridcolumn name="last_name">
<cfgridcolumn name="first_name">
<cfgridcolumn name="age">
</cfgridcolumn>

<cfinput type="text" name="the_last_name" bind="{user_grid.last_name}">

There you go. Enjoy.

Tuesday, November 06, 2007

SQL Server / Date Formatting

Too tired to do a full write up. But here are some helpful links if you are trying to do date formatting / masking on SQL Server:

SQL Server Syntax
http://www.oreilly.com/news/sqlnut_1200.html

SQL Server Conversion Codes
http://msdn2.microsoft.com/en-us/library/ms187928.aspx

SQL Server, Nulls, and SET CONCAT_NULL_YIELDS_NULL

When you try to concatenate string columns in SQL Server, if any of the columns have null as a value, by default the result of the broader concatenation will be null. You can get around this by entering the following:

SET CONCAT_NULL_YIELDS_NULL OFF

For example, consider the following query:

SELECT last_name + ', ' + first_name + ' ' + middle_name AS full_name
FROM person
WHERE person_id = 12345

If person 12345 doesn't have a middle name, and person 12345's middle_name is set to null in the database, then the entire concatenation will resolve to null, and full_name will result in an null / empty string.

However, if you do this:

SET CONCAT_NULL_YIELDS_NULL OFF
SELECT last_name + ', ' + first_name + ' ' + middle_name AS full_name
FROM person
WHERE person_id = 12345

Then the result will be something like:

-----------------------
Doe, John
-----------------------

By the way, this solution works just fine in ColdFusion too. For example:

<cfquery name=""get_name" datasource="ds">
SET CONCAT_NULL_YIELDS_NULL OFF
SELECT last_name + ', ' + first_name + ' ' + middle_name AS full_name
FROM person
WHERE person_id = 12345
</cfquery>

This is especially useful when using cfgrid. CFgrid won't allow you to compose columns that represent more than one database field. For instance, you would have to use one cfgridcolumn for first_name, and a second for last_name. You can't just have both in one column called "Full Name". Unless, that is, you use the above example to create the full_name column thru the database.

Wednesday, October 10, 2007

Multiple LEFT JOINs in MS Access

I had forgotten about this one. In Microsoft Access, if you want to do more than one LEFT JOIN, you have to use parenthesis in the FROM clause. So, for example, instead of just plain old:

SELECT a.columna, b.columnb, c.columnc
FROM tablea AS a LEFT JOIN tableb AS b ON a.id = b.id LEFT JOIN tablec AS c ON a.id = c.id

you would have to do the following:

SELECT a.columna, b.columnb, c.columnc
FROM ((tablea AS a) LEFT JOIN tableb AS b ON a.id = b.id) LEFT JOIN tablec AS c ON a.id = c.id

Otherwise, you get a "Missing Operator" error. Stupid Access.

--Update 10/29/2009--
Incidentally, this should work with other sorts of joins as well.

Friday, August 31, 2007

cfwindow source and cfdiv URL bind strip out <script> tags

This just in. When you use cfwindow or cfdiv to load content dynamically (e.g. thru cfwindow's source attribute, cfdiv's bind attribute (e.g. bind="url:foo.cfm"), or ColdFusion.navigate('foo.cfm')), when the content loads in your window/div, all <script> tags will be stripped from your code.

Consider the following:

<!-------- page.cfm -------->
<cfwindow name="myWindow" source="content.cfm" />

<input type="button" onClick="ColdFusion.Window.show('myWindow')" value="Show the Window">
<!-------- End page.cfm -------->

And the following content page, called by page.cfm
<!-------- content.cfm -------->
<script>

function tellMeSomething (somethingToTell) {

alert('somethingToTell');

}
</script>

<input type="button" onClick=" tellMeSomething('yadda-yadda-yadda'); " value="Tell me Something.">
<!-------- End content.cfm -------->

When page.cfm tells the cfwindow to load conten.cfm, here is the HTML that will be sent to the browser for content.cfm

<div style="overflow: auto; height: 253px; width: 474px;" id="myWindow_body" class="x-dlg-bd">

<input onclick=" tellMeSomething('yadda-yadda-yadda'); " type="button" value="Tell me Something.">
</div>
Notice that the <script tag and its associated function was completely stripped out.

Obviously, this is a problem if the page that you are loading needs to call a JavaScript function. There is a workaround, albeit a very imperfect one. If you put your JavaScript in the calling page (i.e. in the example above, you would put it in page.cfm), it will work.

The problem with the above workaround is that it encourages poor programming practices, and very high coupling between page.cfm and content.cfm.

Wednesday, August 22, 2007

cfajaxproxy and the head tag

*** UPDATE ***

Ok, so slight modification. It appears that your JavaScript only has to appear after the opening <head> tag. And, this only applies to JavaScript that makes calls against the JavaScript proxy generated by the cfajaxproxy tag (Any other JavaScript can appear anywhere you want). However, if you are going to make JavaScript calls against the proxy generated by the cfajaxproxy tag, then you had better do them after the opening <head> tag.

One other caveat: The above only applies to pages with a <head> tag. If your page doesn't have a <head> tag, then you can put any of your JavaScript anywhere you want. The above only applies to pages with a <head> tag.

It would take too long to explain why the JavaScript behaves this way. However, if anyone wants to know the reason that I believe the JavaScript behaves this way, let me know, and I will post it. It has more to do with where ColdFusion posts its JavaScript on the page than with any quirks in the JavaScript itself.

*** END UPDATE ***

Recent experience has shown that the JavaScript proxy generated by cfajaxproxy will not work if you have any user-generated JavaScript that appears outside of the <head> tag. For example, consider the following pages:

Here is the main page:
<!-------- index.cfm -------->

<cfajaxproxy cfc="component.cfc" jsclassname="component_proxy">

<script>

var js_component_proxy = new component_proxy();

var result = js_component_proxy.a_function();

</script>

<cfinclude template="top.cfm">

Some content

<cfinclude template="bottom.cfm">

<-------- End index.cfm -------->

The "Top" include follows. Notice that it has the HTML header in it.
<!-------- start.cfm -------->

<html>

<head>

Header Content

</head>

<body>

<!-------- End start.cfm -------->

And a nice little bottom.cfm to tie everything up nicely.
<-------- end.cfm -------->

</body>

</html>

<-------- End end.cfm -------->

The above will not work. When you run the JavaScript generated by cfajaxproxy, you will get the following JavaScript error:

window:global: mark_arrived has no properties


However, if you copy the user generated JavaScript into the header area marked "Header Content", suddenly everything works fine.

This was a bit of a problem for us. Our site has a page similar to the "start.cfm" page mentioned here, that in addition to many other things, contains the page header data. This means that cfajaxproxy will not work for us if we use any other JavaScript on the page.

We did find a moderately painless workaround. If anyone is interested, post a comment, and I will post the workaround here.

Tuesday, August 21, 2007

cfajaxproxy, Application.cfm, and pain

Recent experience has taught me that if you use cfajaxproxy on a page, and your Application.cfm page outputs anything to the screen, you will get a JavaScript error when you try to call any of the JavaScript functions that call proxy methods. So, for instance, consider the following (which gives an error):

<!-------- Application.cfm -------->
<cfapplication name=""blah">

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<!-------- End Application.cfm -------->



<!-------- Component.cfc -------->
<cfcomponent>

<cffunction name="test_proxy" access="remote" returntype="string">

<cfreturn "success" />

</cffunction>

</cfcomponent>
<!
-------- End Component.cfc -------->



<!-------- index.cfm -------->
<cfajaxproxy
cfc="component"
jsclassname="component_proxy">

<cfoutput>

<script>

var js_component_proxy = new component_proxy();

function js_test_proxy() {
alert(js_component_proxy.test_proxy());
}

</script>

<input type="button" name="a_button" value="Click Me" onclick="js_test_proxy();" />

</cfoutput>
<!-------- End index.cfm -------->

If you run index.cfm?cfdebug, and click the little button, the following error will appear in the little debug window:

window:global: parseJSON

This error took a long time to isolate, and a while to fix. I don't know of anywhere in the livedocs where this is documented. However, if you have any output in your Application.cfm, even a doctype declaration, beware!!!

Incidentally, we did find a moderately difficult fix. If you are interested in knowing how we fixed this problem, post a comment, and I will post the fix.

CF Ajax goodness and SSL

According to Damon Cooper, one of the lead guys on the ColdFusion 8 product, if you request a page using HTTPS, then any of the AJAX calls that the page makes back to the server will use SSL / encrypted connections.


Researched this one for hours. Finally emailed Damon, and he got me a snappy response. Thanks, Damon!

Wednesday, February 21, 2007

Tuesday, March 07, 2006

SQL Server Express 2005 Remote ODBC Connections

Just downloaded and installed SQL Server Express 2005 yesterday for my development environment. So far, it looks like a suprisingly functional yet free version of SQL Server. I have been pleasantly suprised. However, there was some heartburn involved with getting it to accept Remote (i.e. from another server) ODBC connections from my development ColdFusion server (non .Net). With the help of google, the following website (and several others), and some patience, I was finally able to get it to work this morning:

http://blogs.msdn.com/sqlexpress/archive/2004/07/23/192044.aspx

Here is what I learned in a nutshell:

  1. By default, SQL Server Express 2005 does not allow TCP/IP connections. You have to turn that on in the Connection Manager. The how-to is listed in the article that I mention above.

  2. By default the SQLBrowser service is turned off. You have to go into Administrative Tools / Services and turn it on. I set it to manual, and then clicked "Start", however you may wish for it to always be running.

  3. Since the computer that I have SQL Server Express 2005 running on is inside a firewalled local network that is not connected to the outside world, I don't have Windows firewall running on the database machine. However, if you do have SQL Server Express 2005 running on a machine with Windows firewall, or any other firewall running on it, you may need to try fiddling with the firewall settings to allow connections to the machine.
I think that's all I had to do. If I remember anything else, I will post it here.

Tuesday, November 08, 2005

Windows XP Home Administrator

Wow. I must be an idiot. I never knew that you could log in as Administrator on Windows XP Home.

To do so, when you come the Windows Home Login Screen (the one with a button for each user, and when you click the button, it gives you a password field) simply press Ctrl-Alt-Delete twice (or so), and you will get the standard login screen with a username and password field. For username put the username, for password put the Administrator password, and you are logged in as Administrator. On some computers, if you don't specify a password, it just leaves it as blank. Amazing.

Monday, June 20, 2005

MS Access: List Table Names

I finally figured out how to query a list of all table names out of MS Access. There is a hidden table called MSysObjects. Many thanks to http://eis.bris.ac.uk/~ccmjs/access_section.html for the information.

To get a list of table names from Access (or form names, or query names, etc.), simply query the MSysObjects table, where type=1. Easy.