Shaun Mccran

My digital playground

02
O
C
T
2009

Dynamically colouring swfs using Flashvars to match generic templates

One of the application frameworks that I regularly work in is an entirely generic, white box solution. It builds itself based on some instantiation variables. This includes the CSS for that instance of the application. More recently I was integrating a swf object that would be used on hundreds of instances of this application, but it was generically coloured, which just wouldn't work. I needed to somehow have the flash object fit the CSS style of that instance of the App.

Solution

The flash object accepts a series of Flashvars that are passed into it on load. Like this:

view plain print about
1var flashvars = {};
2    flashvars.path = "value";
3    flashvars.upload_url = "value";
4    flashvars.color = "value";
5    flashvars._border_color = "value";

So all I had to do was find a common element in the framework, pick its colour CSS property out, and inject it into the Flashvars object. Using the prototype method of 'getStyle' we can pass in the id of an element, and retrieve its CSS property, IE the background-color.

view plain print about
1var swfBg = $('element id').getStyle('background-color');
2swfBg = swfBg.parseColor().replace('#','');
3alert(swfBg);

This returns an RGB value, so we run it through the 'parseColor' method, and strip the hash. This gives us a valid Hex colour value, which we use in the Flashvars instead of a hard coded colour code.

view plain print about
1var flashvars = {};
2    flashvars.path = "value";
3    flashvars.upload_url = "value";
4    flashvars.color = swfBg;
5    flashvars._border_color = "value";

03
S
E
P
2009

Changing a table row colour with JavaScript

I was recently looking at a way of people selecting many records from a data display. You know the usual table layout of data, populated with a query object. I decided on a column of checkboxes so that a user could select multiple records. The only issue with this was that it is not the most visible indicator of whether a record is selected.

So I thought I would add a JavaScript function to change the table row background colour, to show selected records.

Firstly here is a simple mock up of a table, populated with a list.

view plain print about
1<cfset variables.myList = '1,2,3,4,5,6,7,8,9,10,11,12,13,14'>
2<cfparam name="variables.odd" default="">
3
4<cfoutput>
5<table width="200" border="0" cellspacing="0" cellpadding="2">
6<cfloop list="#variables.myList#" index="variables.row">
7    <cfif (variables.row MOD 2) IS 1>
8        <cfset variables.odd = true>
9    </cfif>
10    <tr <cfif variables.odd> bgcolor="CCCCCC" </cfif> >
11        <td>Row #variables.row#</td>
12        <td>Data 2</td>
13        <td align="middle"><input type="checkbox" id="rowId" name="rowId" value="#variables.row#" onclick="row_color(this,#variables.odd#)"></td>
14    </tr>
15    <cfset variables.odd = false>
16</cfloop>
17</table>
18</cfoutput>

The table rows are alternately coloured based on a basic odd/even check. This value is also passed to the function, as if we uncheck the record we want the row to return to its original colour.

Next we have the JavaScript function that each checkbox is running when it is clicked. The 'row_color' function uses the 'this' variable to work back up two elements using the 'parentNode' function. This targets the table row (tr) tag, and changes its colour to whichever value is set at the top of the script. There are two colour off values as the table rows are alternately coloured, and we want them to return to their original colour when unselected.

view plain print about
1<scr/ipt type="text/javascript">
2    var color_on = '#FFE7DF';
3    var color_off_1 = '#CCCCCC';
4    var color_off_2 = '#FFFFFF';
5    
6    function row_color(pTarget,row)
7    {
8        var pTR = pTarget.parentNode.parentNode;
9
10        if(pTR.nodeName.toLowerCase() != 'tr')
11        {
12            return;
13        }
14
15        if(pTarget.checked == true)
16        {
17            pTR.style.backgroundColor = color_on;
18        }
19        else
20        {
21            if(row == 1)
22            {
23                pTR.style.backgroundColor = color_off_1;
24            }
25            else
26            {
27                pTR.style.backgroundColor = color_off_2;
28            }
29            
30        }
31    }
32</scr/ipt>

20
A
U
G
2009

Connecting Select form fields based on data selections Pt 3

I've been exploring various methods of using JQuery to populate Select form fields. In the previous article I used an intermediary file to act as a handler for the JSON returned object. In this last article I have removed the extra handler template, interfacing directly with the CFC.

Firstly there are some small changes to the JQuery url call.

view plain print about
1<scr/ipt src="jquery-1.2.3.js" type="text/javascript"></script>
2<scr/ipt src="select-chain.js" type="text/javascript" charset="utf-8"></script>
3<scr/ipt type="text/javascript">
4 jQuery.noConflict();
5 jQuery(function () {
6 var type = jQuery('#series');
7 var sp = jQuery('#issueno');
8 var selectedSeries = jQuery('#series').val();
9
10 type.selectChain({
11 target: sp,
12 url: 'jquerySeries.cfc?method=getIssueNos',
13 type: 'post',
14 data: { ajax: true, returnformat: 'plain', series: selectedSeries }
15 }).trigger('change');
16
17 });
18</script>

Now we are directly referencing the CFC. Simply append the function name as a url parameter. In the "DATA" element we place the data we are passing in the form of key value pairs. This will build all the values into the JQuery url, so the final URL would be:

view plain print about
1jquerySeries.cfc?method=getIssueNos&ajax=true&returnformat=plain&series=selectedSeries

At this point I was getting an parse error, until I found the 'returnFormat' value. Coldfusion will return WDDX encoded packets by default, problem was my handler was looking for Json. Adding this value will stop this.

Next we have the same form as before, there are no changes at all: (here for completeness really)

view plain print about
1<cfset variables.series = createObject("component","jquerySeries").getSeries()>
2 <form action="" method="post">
3 <select name="series" id="series">
4 <cfoutput query="variables.series">
5 <option value="#variables.series.intId#">#variables.series.varName#</option>
6 </cfoutput>
7 </select>
8 <select name="issueno" id="issueno">
9 <option></option>
10 </select>
11 <button type="submit">Submit</button>
12 </form>

Lastly there are one or two small changes to our CFC function.

view plain print about
1<cffunction name="getIssueNos" access="remote" output="false" hint="returns related series issue numbers">
2        <cfargument name="series" type="numeric" required="false" hint="Id of the publication">
3        <cfset var result = "">
4
5        <cfquery name="result" datasource="#application.ds#">
6            SELECT [intIssueNo]
7            FROM [dbo].[tbl_cn_series_issueNos]
8            where intSeriesId = <cfqueryparam value="#arguments.series#" cfsqltype="cf_sql_integer">
9        </cfquery>
10        
11        <cfsetting showdebugoutput="false">
12        <cfset ojson = createObject("component","cfjson")>
13        <cfset theresults = ojson.encode(listToArray(valuelist(result.intIssueNo)))>
14        <cfsetting enablecfoutputonly="true">
15    <cfreturn theresults>
16    </cffunction>

The access method has changed, so we add an "access=remote" value to expose the function as a service. Then we serialize the query result into JSON, and return it. This seems like a much more succinct way of doing this.

18
A
U
G
2009

Connecting Select form fields based on data selections Pt 2

I want to be able to dynamically change a second select field based on the value of the first select field.

Following on from the cfajaxproxy example I wrote last week, where I discovered I could not use ColdFusion 8 functionality on my live server, I have arrived at a variant solution.

In this example I am using a similar JQuery url request to process the output from a CFC. The first template is the form itself. This includes references to the JQuery libraries and the binding of the response to the form elements. It also builds the url request to the 'request_processor.cfm' file, which handles the CFC.

view plain print about
1<scr/ipt src="jquery-1.2.3.js" type="text/javascript"></script>
2<scr/ipt src="select-chain.js" type="text/javascript" charset="utf-8"></script>
3<scr/ipt type="text/javascript">
4 jQuery.noConflict();
5 jQuery(function () {
6 var type = jQuery('#series');
7 var sp = jQuery('#issueno');
8
9 type.selectChain({
10 target: sp,
11 url: 'request_processor.cfm',
12 type: 'post',
13 data: { ajax: true }
14 }).trigger('change');
15
16 });
17</script>

Next build a simple form, and populate the first select field with data from a method.

view plain print about
1<cfif not structisempty(form)>
2 <cfdump var="#form#">
3<cfelse>
4 <cfset variables.series = createObject("component","jquerySeries"). getSeries()>
5 <form action="" method="post">
6 <select name="series" id="series">
7 <cfoutput query="variables.series">
8 <option value="#variables.series.intId#">#variables.series.varName#</option>
9 </cfoutput>
10 </select>
11 <select name="issueno" id="issueno">
12 <option></option>
13 </select>
14 <button type="submit">Submit</button>
15 </form>
16</cfif>

Next is the intermediately file that handles the data manipulation, this is triggered when the user chooses an option from the first select field. It passes through the selected value, and returns the query object. This is then serialised using the cfJson object, to return the data in Json. If you do anything like this remember to watch your debug output, it was destroying my Json response for a good ten minutes before I remembered to turn it off. Doh!

view plain print about
1<cfsetting showdebugoutput="false">
2<cfsetting enablecfoutputonly="true">
3<cfparam name="form.series" default="8">
4<cfset variables.issues = createObject("component","jquerySeries").getIssueNos(series=form.series)>
5<cfset ojson = createObject("component","cfjson")>
6<cfset theresults = ojson.encode(listToArray(valuelist(variables.issues.intIssueNo)))>
7<cfoutput>#theresults#</cfoutput>

Finally a CFC that performs the database functions. This is a pretty straight forward CFC that performs two database queries, the second based on an id passed in from the first.

view plain print about
1<cfcomponent>
2
3    <cffunction name="getSeries" output="false" hint="Returns publication series">
4        <cfset var result = "">
5
6    <cfquery name="result" datasource="#application.ds#">
7        SELECT [intId],[varName]
8        FROM [dbo].[table]
9        Where intActive = '1'
10        Order by varName
11    </cfquery>
12
13    <cfreturn result>
14    </cffunction>
15
16    <cffunction name="getIssueNos" output="false" hint="returns related series issue numbers">
17        <cfargument name="series" type="numeric" required="false" hint="Id of the publication">
18        <cfset var result = "">
19
20        <cfquery name="result" datasource="#application.ds#">
21            SELECT [intIssueNo]
22            FROM [dbo].[table]
23            where intSeriesId = <cfqueryparam value="#arguments.series#" cfsqltype="cf_sql_integer">
24        </cfquery>
25
26    <cfreturn result>
27    </cffunction>
28</cfcomponent>

Once you have these elements hooked up you'll see that the response from the first select field changes the values in the second field. You can download a rar'd version of the code base here.

This works well, but I'm not massively happy about the 'remote_processor' file. I think I'll see if there is a way of directly calling the CFC, and moving the JSON serialisation into the functions.

_UNKNOWNTRANSLATION_ /