3

I have an Ajax request that calls a CFC:

Ajax:

<script>
function PopulateEmailData(){

        $.ajax({
            type: "POST",
            data: $('##emailTicket').serialize(),
            url: "cfcs/emailData.cfc?method=getData&ticket_id=#url.ticketID#",
            beforeSend: function(){
                //$('.loader').show();
            },
            complete: function(){
                 //$('.loader').hide(3000);
            },
            success: function(data) {
                $("##timestampTD").append('emailTracking.timestamp'); 
                $("##senderTD").val('emailTracking.sender');
                $("##recipientTD").val('emailTracking.recipient');
                console.log("PopulateEmailData Called - Success");
            },
            error: function() {
                console.log("PopulateEmailData Called - Error");
            }
        })
    }
    console.log("PopulateEmailData Called");    
</script>

My CFC then queries my database: CFC

<cfcomponent>
    <cffunction name="getData" access="remote" returnType="query">
        <cfargument name="ticket_id" type="any" required="true">

        <!--- localize function variables --->
        <cfset var emailTracking = "">

        <cfquery name="emailTracking" datasource="#datasource#">
            SELECT *
            FROM  email_tracking
            WHERE ticket_id = <cfqueryparam value="#ARGUMENTS.ticket_id#" cfsqltype="cf_sql_varchar">
        </cfquery>

        <cfreturn emailTracking>
    </cffunction>
</cfcomponent>

I can see in my console output that my query data is being returned. What I am trying to do is to fill HTML table data with the results. I am attempting to do it through the success function of my AJAX call.

Here is my HTML table

<table width="100%" class="email_tracking_table">
    <thead>
        <tr>
            <th>Timestamp</th>
            <th>Sender</th>
            <th>Recipient(s)</th>
        </tr>
    </thead>
    <tr>
        <td id="timestampTD"></td>
        <td id="senderTD"></td>
        <td id="recipientTD"></td>
    </tr>
</table>

But what I am seeing is just the text 'emailTracking.timestamp' being added to the TD element, not the retuned data. What am I doing wrong?

4
  • 4
    There are 2 ways to handle this. Have the CFC method return JSON and then use jQuery to populate the table or have the CFC method loop over the query create the HTML and then return it for the ajax just to include it. The former method is the best approach but the latter is easier if you dont know jQuery. Commented Jul 22, 2019 at 15:48
  • 1
    You are currently appending a constant string to your table cell. Look at how your data is returned. In the success handler write: console.dir(data). Then you can see how to access the value you want to write into the cell. Commented Jul 22, 2019 at 15:52
  • I'm not following. So I should be referencing my query results in a different way instead of $("##timestampTD").append('emailTracking.timestamp'); ? Can you give an example? My console.dir(data) doesn't show my data in there. Commented Jul 22, 2019 at 16:56
  • 1
    The .append() method takes an html string. Output the data that’s passed into your success function and see how your data is formatted in JavaScript. Then pass that data into the append() function. Commented Jul 22, 2019 at 18:19

1 Answer 1

4

Problems

  1. If your query can return multiple records, your JS code will need to loop through those results, adding a new <tr> for each record.
  2. Wrapping a JS variable in quotes prevents it from being evaluated. So 'emailTracking.timestamp' (note the quotes) is a string, not a variable.
  3. The actual variable passed to the success() function is named data, not "emailTracking.timestamp". To access the query data, use the data variable.
  4. The CFC may be returning a query, but it's not in the correct format. CF returns wddx format by default, which your jQuery code won't handle correctly. Use a more compatible format like JSON.

Resolution

  1. To request the response in JSON format, add the returnFormat parameter to the ajax url:

    ?method=getData&returnFormat=json&....
    
  2. Set the jquery response dataType to "json", so its automatically deserialized

        ...
        type: "POST",
        dataType: "json",
        url: "..."
        ...
    
  3. Although adding ?returnFormat=json to the url is enough to get back JSON, CF's default format for queries is very ... non-standard. So you may want to modify the CFC to return an array of structures instead. Just don't forget to change the function return type to "array".

    <cffunction name="getData" access="remote" returnType="array">     
        ... code
    
        <cfset local.response = []>
        <cfloop query="emailTracking">
            <cfset arrayAppend(local.response
                              , { "timestamp": emailTracking.timestamp
                                  , "sender": emailTracking.sender
                                  , "recipient": emailTracking.recipient
                                }
                            )>
        </cfloop>
    
        <cfreturn local.response>
    
    </cffunction>   
    

With those changes, the JS data variable will now contain an array of structures which you can loop through and construct your HTML easily enough.

success: function(data) {
    data.forEach(function (item, index) {
        // for demo, log values in each row to console
        console.log(index, item.timestamp, item.sender);
    });
}
Sign up to request clarification or add additional context in comments.

6 Comments

Awesome explanation! Really helps in my understanding of how this whole process works. Thanks so much.
Glad it was helpful.
<cf_understatement>"CF's default format for queries is very ... non-standard." </cf_understatement>
Because CF has always been a little wonky with returning data, especially where JSON comes into play, I've always found it more reliable to do like Ageax suggests and build a specific return value.
@Shawn - I didn't think S.O. would appreciate my real thoughts on the default format, so I was being ... "tactful" ;-)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.