Blog

Blog posts made on 31-May-07
31May
2007
CF Team Member Rakshith Blogging

Rakshith is part of the ColdFusion engineering team in Bangalore, and he is now blogging.

Read More ›

31May
2007
Server Side Printing In ColdFusion 8

This one was not discussed during the usergroup tour, and I have not seen anyone mention it since we released the CF8 public beta, so ...

If you've ever needed server-side printing under programmatic control, ColdFusion 8 introduces a new <CFPRINT> tag. <CFPRINT> prints PDF files (including those created using <CFDOCUMENT>, <CFREPORT> and <CFPDF>) to a printer of your choice. At a minimum, <CFPRINT> requires just the name of the PDF file to be sent to the default system printer, but additional attributes can be used to specify the printer, copy count, the pages to print, as well as to pass lots of other printer settings. The list of available printers (and their names, as must be passed to <CFPRINT>)is listed in the ColdFusion Administrator. And a new supporting GetPrinterInfo() function returns all sorts of information about specified printers.

Read More ›

31May
2007
ColdFusion Ajax Tutorial 3: Live Data Grids

The data grid is critical to all sorts of development on all sorts of platforms and in all sorts of languages. ColdFusion has supported data grids since ColdFusion 2 - first a Java applet, then a Flash control, and in ColdFusion 8 we've added an HTML data grid that can be pre-populated with data, or which can be used to display live data loaded asynchronously.

The basic pre-populated data grid functions much like the <CFGRID> of old, pass it a query and it displays the data. Here is an example (which uses the example tables that come with ColdFusion):

view plain print about
1<cfquery name="artists" datasource="cfartgallery">
2SELECT artistid, lastname, firstname, email
3FROM artists
4ORDER BY lastname, firstname
5</cfquery>
6
7<cfform>
8    <cfgrid name="artists"
9            format="html"
10            striperows="yes"
11            query="artists">

12        <cfgridcolumn name="lastname" header="Last Name" width="100"/>
13        <cfgridcolumn name="firstname" header="First Name" width="100"/>
14        <cfgridcolumn name="email" header="E-Mail" width="200"/>
15    </cfgrid>
16</cfform>

Here a <CFQUERY> retrieves data, and <CFGRID> displays the results. The grid is straight client side HTML with CSS and JavaScript. You have control over look and feel including size, columns, colors, and fonts. And users can sort up and down, resize columns, and more.

The new <CFGRID> also supports Ajax type interaction, where data is not pre-populated, but is asynchronously loaded as needed. Here is a sample data grid:

view plain print about
1<cfwindow initshow="true" center="true"
2            width="430" height="340" title="Artists">

3
4<cfform>
5    <cfgrid name="artists"
6            format="html"
7            pagesize="10"
8            striperows="yes"
9            bind="cfc:artists.getArtists({cfgridpage},
10                                        {cfgridpagesize},
11                                        {cfgridsortcolumn},
12                                        {cfgridsortdirection})"
>

13        <cfgridcolumn name="lastname" header="Last Name" width="100"/>
14        <cfgridcolumn name="firstname" header="First Name" width="100"/>
15        <cfgridcolumn name="email" header="E-Mail" width="200"/>
16    </cfgrid>
17</cfform>
18
19</cfwindow>

This data grid is displayed in a window created using the new <CFWINDOW> tag (for no good reason other than I like the look of it). The data grid itself has no passed query, instead, it is bound to artists.cfc. When the data grid needs data it fires an asynchronous call to the getArtists() method in artists.cfc, and passes it four pieces of information: the current page, the page size (specified previously in the pagesize attribute), and the column being sorted on and sort direction (if the user opts to sort data). <CFGRID> thus requests data, and simply displays whatever ColdFusion returns, automatically supporting paging (assuming there are enough rows to so warrant).

Now for the CFC:

view plain print about
1<cfcomponent output="false">
2
3    <cfset THIS.dsn="cfartgallery">
4
5    <!--- Get artists --->
6    <cffunction name="getArtists" access="remote" returntype="struct">
7        <cfargument name="page" type="numeric" required="yes">
8        <cfargument name="pageSize" type="numeric" required="yes">
9        <cfargument name="gridsortcolumn" type="string" required="no" default="">
10        <cfargument name="gridsortdir" type="string" required="no" default="">
11
12        <!--- Local variables --->
13        <cfset var artists="">
14
15        <!--- Get data --->
16        <cfquery name="artists" datasource="#THIS.dsn#">
17        SELECT artistid, lastname, firstname, email
18        FROM artists
19        <cfif ARGUMENTS.gridsortcolumn NEQ ""
20            and ARGUMENTS.gridsortdir NEQ "">
21            ORDER BY #ARGUMENTS.gridsortcolumn# #ARGUMENTS.gridsortdir#
22        </cfif>
23        </cfquery>
24
25        <!--- And return it as a grid structure --->
26        <cfreturn QueryConvertForGrid(artists,
27                            ARGUMENTS.page,
28                            ARGUMENTS.pageSize)>

29    </cffunction>
30
31</cfcomponent>

The getArtists returns a structure (containing data in the format required by the data grid), and accepts four arguments, the same four arguments passed in the client side bind attribute. The first two are always passed by the client, and so they are required. The latter two are only passed if the user clicks on a column header to sort the data, and so those arguments are not required and default to "". <CFQUERY> performs the actual data retrieval, conditionally sorting the data if sorting is required. And finally, the new QueryConvertForGrid() function extracts the desire data subset (using the passed page and pagesize values) and formats it as a structure which is returned to the data grid.

This is a basic example, and we'll look at additional functionality in future posts.

Read More ›

31May
2007
ColdFusion Ajax Tutorial 2: Related Selects

Many of us have built related select controls, forms with two (or more) drop down <SELECT> controls, where making a change in one control causes the available selections in the related control to change. For example, selecting a category in one control displays category products in a related control, or selecting a state in one control updates a related control with the cities in that state.

These controls are typically implemented using client side JavaScript to process arrays of data embedded in the page itself. Every possible combination and option is embedded in JavaScript in the page, and client side scripts update controls based on selection changes in other controls.

ColdFusion 8's new Ajax functionality makes this kind of interface really easy, without requiring any client-side scripting, and without requiring that all of the data be embedded in the generated page. Rather, <CFSELECT> controls may be bound to ColdFusion Component methods that are asynchronously invoked as needed.

To demonstrate this, here is a complete working example which uses one of the example databases that comes with ColdFusion. First the ColdFusion Component:

view plain print about
1<cfcomponent output="false">
2
3    <cfset THIS.dsn="cfartgallery">
4
5    <!--- Get array of media types --->
6    <cffunction name="getMedia" access="remote" returnType="array">
7        <!--- Define variables --->
8        <cfset var data="">
9        <cfset var result=ArrayNew(2)>
10        <cfset var i=0>
11
12        <!--- Get data --->
13        <cfquery name="data" datasource="#THIS.dsn#">
14        SELECT mediaid, mediatype
15        FROM media
16        ORDER BY mediatype
17        </cfquery>
18
19        <!--- Convert results to array --->
20        <cfloop index="i" from="1" to="#data.RecordCount#">
21            <cfset result[i][1]=data.mediaid[i]>
22            <cfset result[i][2]=data.mediatype[i]>
23        </cfloop>
24
25        <!--- And return it --->
26        <cfreturn result>
27    </cffunction>
28
29    <!--- Get art by media type --->
30    <cffunction name="getArt" access="remote" returnType="array">
31        <cfargument name="mediaid" type="numeric" required="true">
32
33        <!--- Define variables --->
34        <cfset var data="">
35        <cfset var result=ArrayNew(2)>
36        <cfset var i=0>
37
38        <!--- Get data --->
39        <cfquery name="data" datasource="#THIS.dsn#">
40        SELECT artid, artname
41        FROM art
42        WHERE mediaid = #ARGUMENTS.mediaid#
43        ORDER BY artname
44        </cfquery>
45    
46        <!--- Convert results to array --->
47        <cfloop index="i" from="1" to="#data.RecordCount#">
48            <cfset result[i][1]=data.artid[i]>
49            <cfset result[i][2]=data.artname[i]>
50        </cfloop>
51
52        <!--- And return it --->
53        <cfreturn result>
54    </cffunction>
55
56</cfcomponent>

This CFC contains two methods. getMedia returns all of the media types in the art catalog database, and getArt accepts a media id and returns any art that is associated with that passed id. Both methods convert their results into two dimensional arrays, with the first dimension containing the id (to be used as the value in the <SELECT> control) and the second containing the display text. (For now, this two dimensional array is the format required by <CFSELECT>).

Now for the form itself:

view plain print about
1<cfform>
2
3<table>
4    <tr>
5        <td>Select Media Type:</td>
6        <td><cfselect name="mediaid"
7                bind="cfc:art.getMedia()"
8                bindonload="true" />
</td>
9    </tr>
10    <tr>
11        <td>Select Art:</td>
12        <td><cfselect name="artid"
13                bind="cfc:art.getArt({mediaid})" />
</td>
14    </tr>
15</table>
16
17</cfform>

The form contains two <CFSELECT> controls, one named "mediaid" and the other named "artid".

"mediaid" is bound to cfc:art.getMedia(), and so to obtain the list of media types to populate the control, the client makes an asynchronous call to the getMedia method in art.cfc, and populates the list with the returned array. As we'd want this control to be automatically populated when the form loads, bindonload is set to "true", this way the getMedia() call is fired automatically at form load time.

"artid" is bound to the getArt method in art.cfc. This method requires that a mediaid be passed to it, and so {mediaid} is used so as to pass the currently selected value of control mediaid (the first <CFSELECT>). Because these two controls are bound together, the second dependant on the first, ColdFusion automatically generates JavaScript code that forces artid to be repopulated with newly retrieved data whenever mediaid changes.

This example binds just two controls, but this mechanism can be used to relate as many controls as needed, and not just <CFSELECT> controls either.

Read More ›

31May
2007
ColdFusion Ajax Tutorial 1: Auto-Suggest

I plan to post a series of examples demonstrating how to use the new Ajax functionality in ColdFusion 8 (many based on examples used during our recent usergroup tour). The first one I'll start with is the auto-suggest control. Auto-suggest is a modified text input box, one that displays suggestions as the user types. The auto-suggest control in ColdFusion 8 can be used in two ways, with local client-side data, and with asynchronous calls back to ColdFusion.

Here's a simple client-side data example (which uses one of the CF8 example databases, so this should work for you as is):

view plain print about
1<!--- Get data --->
2<cfquery datasource="cfartgallery" name="data">
3SELECT artname
4FROM art
5ORDER BY artname
6</cfquery>
7
8<!--- The form --->
9<cfform>
10Art:
11<!--- Populate auto-suggest control --->
12<cfinput type="text"
13        name="artname"
14        autosuggest="#ValueList(data.artname)#">

15</cfform>

This form displays a simple text box, but as text is entered, suggestions are displayed. The list of suggestions are passed to the autosuggest attribute which accepts a comma delimited list. The list could be hardcoded, but here ValueList() is being used to dynamically build a list based on a prior database lookup.

This is not an Ajax control in that lookups are not asynchronous, there is no communication back to the server to retrieve data, all data is local. This is actually a preferred form of auto-suggest for smaller lists.

For longer lists asynchronous interaction is indeed preferred, and the auto-suggest control supports this by allowing asynchronous calls to a ColdFusion component. Here is a sample CFC:

view plain print about
1<cfcomponent output="false">
2
3<cfset THIS.dsn="cfartgallery">
4
5    <!--- Lookup used for auto suggest --->
6    <cffunction name="lookupArt" access="remote" returntype="array">
7 <cfargument name="search" type="any" required="false" default="">
8
9 <!--- Define variables --->
10 <cfset var data="">
11 <cfset var result=ArrayNew(1)>
12
13 <!--- Do search --->
14 <cfquery datasource="#THIS.dsn#" name="data">
15 SELECT artname
16 FROM art
17 WHERE UCase(artname) LIKE Ucase('#ARGUMENTS.search#%')
18 ORDER BY artname
19 </cfquery>
20
21 <!--- Build result array --->
22 <cfloop query="data">
23 <cfset ArrayAppend(result, artname)>
24 </cfloop>
25
26        <!--- And return it --->
27 <cfreturn result>
28    </cffunction>
29    
30</cfcomponent>

This CFC has a single method named lookupArt which accepts a string and performs a query to find all matches that start with the specified value. Auto-suggest requires that results be returns in a single dimensional array (for now, hopefully this will change before we ship the final product), and so the code populates an array with the results which are then returned.

Now for the modified form code to use this CFC and method:

view plain print about
1<cfform>
2Art:
3<cfinput type="text"
4        name="artname"
5        autosuggest="cfc:art.lookupArt({cfautosuggestvalue})">

6</cfform>

Here the autosuggest points to a CFC, and as the CFC (I named it art.cfc) is in the current folder, no path needs to be specified. When a user enters a value, generated JavaScript code triggers an asynchronous calls to the lookupArt method in art.cfc. {cfautosuggestvalue} gets automatically replaced with whatever value the user has entered, and that value is then used by the CFC in the lookup. When an array of results get returned the auto-suggest list gets populated.

Auto-suggest does not get any cleaner and simpler than this.

Read More ›

31May
2007
Apollo To Get An Embedded Database

I've been waiting for this one to be announced, and Mike Chambers just blogged it - Apollo will include an embedded SQLite engine which can be used for local database storage, and which will be invaluable to apps that need to support offline processing.

Read More ›

31May
2007
Ashwin Matthew's Behind The Scenes Peek

Ashwin Matthew has shared a peek at what has been going on behind the scenes while racing to get CF8 out of the door.

Read More ›