views:

614

answers:

4

I've simplified this example as much as I can. I have a remote function:

<cfcomponent output="false">
<cffunction name="Read" access="remote" output="false">
    <cfset var local = {}>

    <cfquery name="local.qry" datasource="myDatasource">
    SELECT PersonID,FirstName,LastName FROM Person
    </cfquery>
    <cfreturn local.qry>
</cffunction>
</cfcomponent>

And using the jQuery $.ajax method, I would like to make an unordered list of everyone.

    <!DOCTYPE HTML>
    <html>
    <head>
    <script src="http://www.google.com/jsapi"&gt;&lt;/script&gt;
    <script type="text/javascript">
    google.load("jquery", "1");
    </script>
    <script type="text/javascript">
    jQuery(function($){
    $.ajax({
            url: "Remote/Person.cfc?method=Read&ReturnFormat=json",
            success: function(data){
                var str = '<ul>';
// This is where I need help:
                for (var I=0; I<data.length; I++) {
                    str += '<li>' + I + data[I][1]+ '</li>'
                }
                str += '</ul>';
                $('body').html(str);
            },
            error: function(ErrorMsg){
               console.log("Error");
            }
        });
    });
    </script>
    </head>
    <body>
    </body>
    </html>

The part where I'm lost is where I'm looping over the data. I prefer to the use jQuery $.ajax method because I understand that $.get and $.post don't have error trapping.

I don't know how to handle JSON returned from the cfc.

+1  A: 

I'm not very familiar with ColdFusion but have you tried setting the data type to JSON?

$.ajax({
    url: 'Remote/Person.cfc?method=Read&ReturnFormat=json',
    dataType: 'json',
    success: function(response) {
        var data = response.DATA;
        var str = '<ul>';

        for (var I = 0; I < data.length; I++) {
            str += '<li>' + I + data[I][1] + '</li>';
        }

        str += '</ul>';

        $('body').html(str);
    },
    error: function(ErrorMsg) {
       console.log('Error');
    }
});

That should work if the data you're getting back resembles something like:

[["PersonID1", "FirstName1", "LastName1"],["PeronID2", "FirstName2", "LastName2"]] .. etc

If the above doesn't work if you could show the raw JSON data being returned by your request I should be able to easily fix it.

Also, not sure if it was in your code, but you missed a semi-colon at the end of the line in the for loop.

anomareh
Thanks for catching the missing semi-colon. The data I'm getting back is: {"COLUMNS":["PERSONID","FIRSTNAME","LASTNAME"],"DATA":[[1001,"Scott","Wimmer"],[1002,"Phillip","Senn"],[1003,"Paul","Nielsen"]]}Also, I don't know why, but the error condition is now being executed rather than the success condition.
cf_PhillipSenn
@cf_PhillipSenn Try my edit. If it's still executing the error condition `console.log(ErrorMsg)` instead of a string and let me know what the error is.
anomareh
+2  A: 

The easiest way would be to visually see how the returned JSON data is structured. Then it shouldn't be too hard to transverse the JS object. Have you tried JSON Visualization? http://chris.photobooks.com/json/default.htm

If all you need is the PersonID, you can return array or list of PersonID from CF as well.

Or optionally, you can ask CF to return Plain text, with all the <li>'s generated. The message passed through ajax will be larger, but you'll have less JS code to maintain. CFML is easier to maintain, right? :)

Henry
+1  A: 

Options :

In your case I'd put

<cffunction name="keywordAutoComplete" access="remote" 
            returntype="struct" returnformat="JSON" >

BUT

this does the same thing as returntype="string" returnformat="plain" + <cfreturn serializeJSON(query) > and that's a problem form jQuery point of view because you get ugly JSON even if you use serializeJSON srerialization by columns.

  1. You can make JSON string manually through cfloop and concatenation :/
  2. Use cfjson.cfc which overrides serializeJSON
  3. Go to Ben Nadel's site and take his toJSON method and modify it somehow to fit your needs

Other thing is serializeJSON, returns uppercased keys, so pay attention, use lcase() or write .LIKETHIS in js.

PS: Try this for dynamic creaiton of html in jQuery:

var someLiElement = $('<li />').addClass('custom_class')
                 .text('Foo bar')
                 .attr('id', 'custom_id' + someInteger)

then append method to parent element

zarko.susnjar
@anomareh "[['PersonID1', 'FirstName1', 'LastName1'],['PeronID2', 'FirstName2', 'LastName2']] .. " is NOT JSON, it's a string with nice brackets ;)
zarko.susnjar
@zarko I have a thing against double quotes :p
anomareh
+2  A: 

Looks like the result is in json format(check the docs http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=Tags_f_21.html). "If you specify returnformat="json" and the function returns a query, ColdFusion serializes the query into a JSON Object with two entries, and array of column names, and an array of column data arrays. For more information see SerializeJSON." http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=Tags_f_21.html

So the first array(data.COLUMNS should be an array of column names. data.COLUMNS[0] would give you the name of the first column. data.DATA[0] would give you the first row of the query.

A nice trick is to use console.log(data) in chrome or firebug console to view the data in it's structured form.

I didn't test this, but it should be close. Just generating a basic table from the data.

$.ajax({
    url: 'Remote/Person.cfc?method=Read&ReturnFormat=json',
    dataType: 'json',
    success: function(response) {
        var str = '<table><tr>';
        var i;
        var j;

        //loop over each column name for headers
        for (i = 0; i < response.COLUMNS.length; i++) {
              str += '<th>' + response.COLUMNS[i] + '</th>';
          }
        }
        str += '</tr>';

        //loop over each row
        for (i = 0; i < response.DATA.length; i++) {
          str += '<tr>';
          //loop over each column
          for (j = 0; j < response.DATA[i].length; j++) {
              str += '<td>' + response.DATA[i][j] + '</td>';
          }
          str += '</tr>';
        }
        str += '</table>';

        $('body').html(str);
    },
    error: function(ErrorMsg) {
       console.log('Error');
    }
});
Lee
Thanks for helping me realize that data was in caps, missed that. Your answer also suffers from the same problem though. `var data = response.data;` should be `var data = response.DATA;` also your for loops are messed up. The first should be `response.COLUMNS.length` and `response.COLUMNS[i]` and your second and third should be `data.length` and `data[i].length`, `data[i][j]` respectively.
anomareh
Oops. I thought the parameter was data and forgot about the reassignment. So, I just changed "data" to "response" and removed "data = response.data".
Lee