views:

2357

answers:

5

Is it possible to assign variables to the client scope using JavaScript? More specifically, I'm trying to assign a value after it is returned from an AJAX call.

I understand that ColdFusion is run on the server side and JavaScript on the client side, but with the proliferation of AJAX, I'm curious if something like this might be possible. Thank you.

+2  A: 

I dont knoew anything about CF, but usually this is done by posting a name/value pair to the server, where the server picks up that value and sticks it into a variable. You can also use GET if you wanted to, and you can do both of these things using AJAX. Another silly hack is to do something like this in javascript:

var img = new Image(); img.src = "http://myserver.com/something.cfm?name=value&anothername=anothervalue";

after that, the server will perform a GET and pass those 2 values to the server. no image will be displayed to the client because: a) you dont add it to the DOM b) its not really an image anyway.

mkoryak
In CF, your first suggestion is basically what you would do -- pass the name/value pair back to a CFC method that would set the client variable.
Ben Doom
+1  A: 

use CFAJAXPROXY (new in CF8), and call a method on your CFC that set the var in Client scope.

Henry
A: 

Use jQuery, then you can use the getJSON() method to send data back to CF web services (i.e. functions with access="remote"), and return results back to JS again.

With CF8's returnformat="json" on functions, this is nice and easy.

(With earlier versions, you need to use cfjson (or similar) to convert data.)


As a quick (and entirely untested) example...

<cffunction name="MyRemoteFunc" returntype="Struct" access="remote" returnformat="json">
    <cfargument name="Name"      type="String"/>
    <cfargument name="Birthday"  type="Date"/>

    <cfset Session.UserDetails.Name = Arguments.Name />
    <cfset Session.UserDetails.Age  = DateDiff('yyyy',Now(),Arguments.Birthday) />
    <cfset Session.UserDetails.Id   = RandRange(1,100) />

    <cfreturn Session.UserDetails />
</cffunction>


<script type="text/javascript">

    function setUserDetails(name,birthday)
    { 
        $j.getJSON
            ( 'http://mydomain/stuff/remote.cfc?method=MyRemoteFunc'
            , { name:arguments.name , birthday:arguments.birthday }
            , setUserDetailsResponse
            );
    }

    function setUserDetailsResponse( result )
    {
        alert( 'Hello '+result.name+', you are '+result.age' years old and your Id is '+result.id+'.' );
    }

</script>
Peter Boughton
This doesn't set the variable to the client scope. If I use <cfdump var="#client#" /> after running your code, it wouldn't display anything.
ibjhb
Every where you see "Session", use "Client" instead, if that's what you want.
Peter Boughton
+2  A: 

Peter Boughton was pretty much dead on in his concept, but you asked how to write client variables, and he didn't test his code. Also, what you're trying to do would be called a ClientFacade, so I've written (and tested) a ClientFacade CFC and companion JavaScript. Note that I'm using jQuery because I never go anywhere without it. ;)

ClientFacade.cfc:

<cfcomponent output="false"
  hint="acts as a remote facade for the client scope">

    <cffunction name="set" output="false" access="remote"
      returntype="boolean" hint="sets a value into the client scope">
     <cfargument name="name" type="string" required="true"/>
     <cfargument name="val" type="any" required="true"/>

     <!--- you should sanitize input here to prevent code injection --->

     <cfscript>
      try {
       client[arguments.name] = arguments.val;
       return(true);
      }catch (any e){
       return(false);
      }
     </cfscript>
    </cffunction>

    <cffunction name="get" output="false" access="remote" returntype="any"
      hint="gets a value from the client scope">
     <cfargument name="name" type="string" required="true"/>
     <cfargument name="defaultVal" type="any" required="false"
            default=""/>

     <!--- you should sanitize input here to prevent code injection --->

     <cfscript>
      if (structKeyExists(client, arguments.name)){
       return(client[arguments.name]);
      }else{
       if (len(trim(arguments.defaultVal)) eq 0){
        return('');
       }else{
        return(arguments.defaultVal);
       }
      }
     </cfscript>

    </cffunction>

</cfcomponent>

test.cfm:

<script type="text/javascript"
  src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js"&gt;
  </script>
foo:<input type="text" name="foo" id="foo"/>
<button id="setValue">Set Value</button>
<button id="alertValue">Alert Value</button>

<script type="text/javascript">
    $(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);
       }
      );
      e.preventDefault();//prevent the button from doing anything else
     });

     //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('Was not able to set the client var :(');
        }
       }
      );
      e.preventDefault();//prevent the button from doing anything else
     });
    });
</script>

I think that's everything you wanted. Let me know if I missed anything.

Adam Tuttle