using jQuery AJAX to post JSON to a CFC
Asked Answered
D

3

6

I'm trying to use Jquery/AJAX/JSON with a CFC to send an email (easy right?) After spending many hours trying to find one complete example of how this should work, I'm getting close but am stuck on the last part. My fail is evident.

I am getting an error of "Unsupported Operation. Check application log for more details." coming back from (I think) ColdFusion.

The GET request that generates that message is coming from the following URL:

http://www.dumbass.com/CFIDE/componentutils/cfcexplorer.cfc?method=getcfcinhtml&name=blah.www.test&path=/blah/www/test.cfc

I am able to call my CFC in a browser, which does send a basic test email:

http://servername/test.cfc?method=sendMail

The form post to the CFC is being sent along as such:

method=sendMail&name=BOB&email=bob%40bitchin.com&subject=Message+from+contact+form&message=bob+is+really+bitchin

Here's the jQuery

$.ajax({
    type: "POST",
    url: "test.cfc?method=sendMail",
    data: {
        "name": $("#footer-form #name2").val(),
        "email": $("#footer-form #email2").val(),
        "subject": "Message from contact form",
        "message": $("#footer-form #message2").val()
    },
    dataType: "json",
    success: function(data) {
        if (data.sent == "yes") {
            $("#MessageSent2").removeClass("hidden");
            $("#MessageNotSent2").addClass("hidden");
            $(".submit-button").removeClass("btn-default").addClass("btn-success").prop('value', 'Message Sent');
            $("#footer-form .form-control").each(function() {
                $(this).prop('value', '').parent().removeClass("has-success").removeClass("has-error");
            });
        } else {
            $("#MessageNotSent2").removeClass("hidden");
            $("#MessageSent2").addClass("hidden");
        }
    }
});

Here is the CFC, (not even trying to use the form fields submitted):

 <cfcomponent output="false" access="remote">
   <cffunction name="sendMail" access="remote" returntype="void">
     <cfmail from="[email protected]" 
      to="[email protected]" subject="duh!!!">
      You got mail!
     </cfmail>
  </cffunction>

The AJAX is bringing back the HTML created for the fail message: "Unsupported Operation. Check application log for more details.".

I'm on a shared CF machine and don't have access to the application logs.Is it passing the data as JSON that is causing me grief? Should I use serialize() on the form instead?

Within the AJAX Jquery I have test.cfc?method=sendMail. Should I put the method within the 'data' block of the AJAX call?

I've got fiddler installed, and am looking at headers, but am still at a loss as to why submitting data to a CFC via Jquery and AJAX should be so much of a mystery.

If anyone can straighten me out or point me to a working example, I would be very appreciative.

UPDATE

After reviewing my javascript - I saw that I had a different function also being called by the form submit - which was causing the "Check application log for more details". Here is the function that was causing the issue for me:

 $(document).ready(function () {
            //this function was getting called in addition to one posted     
            // above. 
            $("input#submit1").click(function(){
                console.log('WTF');
                console.log($('form#footer-form').serialize());
                $.ajax({
                    type: "POST",
                    // this is where I wasn't specifying the method!
                    // it should have been test.cfc?method=sendMail
                    url: "test.cfc", //process to mail
                    // still thinking about serialize to make this flexible
                    data: $('form#footer-form').serialize(),
                    success: function(msg){
                        $("#thanks").html(msg) //hide button and show thank you
                        $("#form-content").modal('hide'); //hide popup  
                    },
                    error: function(){
                        alert("failure");
                    }
                });
            });
        });

Here is my updated CFC which is "working":

 <cffunction name="sendMail" access="remote" returnformat="json" returntype="any">
   <cfargument name="name" required="true" />     
   <cfargument name="subject" required="true" />
   <cfargument name="email" required="true" />
   <cfargument name="message" required="true" /> 



      <cfmail from="[email protected]" 
       to="[email protected]"   subject="#subject#">
      Owning it!
     #name# #subject# #email# #message#
      </cfmail>

      <cfset result ='{"sent":"yes"}'> 

    <cfreturn result />

   </cffunction>

The last bit I'm struggling with is how to properly allow the use of returntype="json" and how to create the return value for that to happen. I have returntype="any" because I was getting an error when I had returntype="json". I would like to use returntype = "json". However this:

<cfset result ='{"sent":"yes"}'> 
<cfreturn result />

throws an error. What is the correct way to create a similar structure so I can use returntype="json"? I'm sure in the future I will want to return JSON from CFC's and don't want to have to build the strings manually ... if that makes any sense.

ie

<cfif success>
  <cfset result ='{"sent":"yes"}'> 
<cfelse>
   <cfset result ='{"sent":"no"}'>
</cfif>

How can I make "result" such that I can use returntype="json"?

Destructible answered 10/4, 2016 at 1:23 Comment(4)
the ajax is POST...not GET. Thus when you try it in browser is different than using the ajax. Also is all of this on same domain as page ajax is being done from?Spud
all requests are on the same domain.Destructible
after reviewing my code ... I found I had conflicting javascript functions. before I found the JS posted above, I had tried to write my own, which didn't include the method in the URL being called. once I removed that ... I no longer get the error "Unsupported Operation. Check application log for more details." I suspect this error was being returned because the URL didn't specify the method.Destructible
Yes missing method name is definitely the reason. Without it the CF server thinks you are trying to browse the CFC and you get redirected to the cfcexplorer, ie /CFIDE/componentutils/cfcexplorer.cfc?method=getcfcinhtml&name=..... As you noted, the error message was coming from that page, not the original cfc requested in the ajax call.Multifoliate
Z
3

Instead of test.cfc use a test.cfm page. Here is the code for it:

<cfswitch expression="#url.method#">

<cfcase value="sendMail">
     <cfmail from="[email protected]" 
      to="[email protected]" subject="duh!!!">
      You got mail!
     </cfmail>

    <cfset result = structNew()>
    <cfset result['sent'] = true />
    <cfoutput>#SerializeJSON(result)#</cfoutput>

</cfcase>

</cfswitch>

you also need to adjust a bit the javascript

the call should be to

url: "test.cfm?method=sendMail",

and instead of

if (data.sent == "yes") {

you need

if (data.sent) {
Zedoary answered 10/4, 2016 at 5:54 Comment(2)
Just keep in mind that while it can technically be done with a .cfm script, it is a lot harder to control extra white space / other output in a cfm script than a cfc. Extraneous output can cause problems parsing or sometimes break the JSON string.Multifoliate
Agreed, my point is, the test.cfm page would return the meaningful error message that url.method was not defined, which would make debugging way faster.Zedoary
M
3

don't want to have to build the strings manually

Yes, definitely do not roll-your-own JSON. However, do not confuse returnType and returnFormat. The returnType is the type of object to return, such as a query, structure, array, etcetera. What you are thinking of is returnFormat, which controls how the object is returned to the caller: json, wddx or plain.

While you can also use returnFormat in the function signature, my preference is to omit any formats from the signature and keep the function flexible. Since you ultimately want to return a structure, use that as the function return type (and handle formatting in your ajax call).

 <cffunction name="sendMail" access="remote" returntype="struct">

Just be careful with key names when creating the result structure. Unfortunately, CF converts all key names to upper case by default. That means the javascript variable will be data.SENT, instead of data.sent. To preserve the case, use associative array notation instead. (Note, the example returns a boolean value ie true/false rather than a string);

 <!--- Default behavior upper cases key names, ie {"SENT": true} --->
 <cfset resultStruct = {sent = true} >

 <!--- Preserves key name case, ie {"sent": true} --->
 <cfset resultStruct["sent"] = true >

Then if you want to return the results as JSON, simply append "returnFormat=JSON" as a url parameter in your ajax call. That parameter instructs CF to automatically convert the result (ie struct object) into a JSON string:

url: "test.cfc?method=sendMail&returnFormat=JSON",

Finally, in your success function, use the boolean value like so:

success: function(data) {
    if (data.sent) {
        console.log("success");
    }
    else {
        console.log("failure. do something else.");
    }
}
Multifoliate answered 11/4, 2016 at 0:58 Comment(0)
M
0

use return type String, returnformat plain text and the object that you return can be converted to json with the call SerializeJson(object).

example:

<cffunction name="sendMail" access="remote" returnformat="plain" returntype="String">
   <cfset response = {sent = "yes"}>
   <cfreturn SerializeJson(response)>
</cffunction>
Miscellaneous answered 26/7, 2024 at 17:0 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.