Ask a Grokker: Can I change CF Client Variables with JavaScript?

Yesterday, Ray posted Ask a Jedi: Using ColdFusion Ajax to set Client Variables. Now, far be it from me to steal from Ray -- but what it looks like is that the question asker also posted his question to Stack Overflow; and after composing my response there I decided it would make a good blog entry too.

As it turns out, Ray's response is really clever. I'm quite fond of it, actually. But I still think mine is a bit more robust and closer to what you might call the "right" way to do it.

The question, to save you the clicking if you haven't seen either of those two pages, was how to get and set ColdFusion client variable values with JavaScript. As for dependencies, my solution uses jQuery and the returnFormat parameter added in ColdFusion 8.

What you want to do is write what would be called a Client Facade

ClientFacade.cfc: try { client[arguments.name] = arguments.val; return(true); }catch (any e){ return(false); } if (structKeyExists(client, arguments.name)){ return(client[arguments.name]); }else{ if (len(trim(arguments.defaultVal)) eq 0){ return(''); }else{ return(arguments.defaultVal); } }

And to use this component, you need to write some client-side JavaScript. As I said before, I used jQuery -- because I never leave home without it.

test.cfm: foo: $(document).ready(function(){ //attach functionality to our alert button $("#alertValue").click(function(e){ var clientVal = 'initialdata'; $.getJSON( 'clientFacade.cfc', { method:"get", returnFormat:"json", name:"foo" }, function(d){ clientVal = d; alert(clientVal); } ); //prevent the button from doing anything else e.preventDefault(); }); //attach functionality to our set button $("#setValue").click(function(e){ var success = false; var valu = $("#foo").val(); $.getJSON( 'clientFacade.cfc', { method:"set", returnFormat:"json", name:"foo", "val":valu }, function(d){ success = eval(d); if (!success){ alert('Failure'); } } ); //prevent the button from doing anything else e.preventDefault(); }); }); Note that I'm using "xscript" instead of "script" tags so that Mango will allow me to post it.

This code remotely (via AJAX) accesses ClientFacade.cfc to send data back and forth. It lets you specify a default value when getting, instead of dealing with non existence.

We start with a few simple form fields: a textbox, a button to save the value, and a button to get and alert the value. To demonstrate that it really is working over AJAX and not just reloading the page faster than can be perceived, you could simply CFDump the Client scope on the page. This would show that the values in server memory are changing without the page reloading.

Then, some click event handlers are binded to our buttons that use jQuery's getJSON method to interact with the server, and the return data is managed with anonymous callback functions.

One final note: Notice that in the SET operation, I'm quoting the variable name:"val":valuThis is because "val" is a JavaScript reserved word. I should have thought of that when writing my CFC, but I didn't, and this is how you get around the issue. (Or just rename the CFArgument, but who has time for that?)

in ColdFusion | JavaScript Posted 2009-02-13 01:35

3 responses:

Raymond Camden
Raymond Camden 2009-02-13 1:51 PM #
Nice! Notice, you have a typo (escaped html) around the first paragraph.
Dan G. Switzer, II
Dan G. Switzer, II 2009-02-13 2:10 PM #
Since this is a generic setter/getter, you'd also want to add some logic in the santize section to check for valid client variable names, otherwise you'd leave the door open to someone crashing your website by arbitrarily setting random client variables.

Yes, it's a corner case but something that someone should keep in mind if they take this approach.
Adam
Adam 2009-02-13 2:26 PM #
@Ray, thanks for pointing out the typo. Fixed it. :)

@Dan, yes, some pretty significant sanitization would be required. In general, you wouldn't let the user affect variable name (just its value), but as the methods are remotely available you still want to account for it in case an enterprising hacker tries to hijack the request. I did leave a comment for that, but as it wasn't part of the concept I didn't want to waste time or space on it.

Leave a comment:

Leave this field empty: