RG_ENT
asked on
Cannot pass argument to CFC in Ajax call -- ends up 0 every time.
I have a message forum that I wrote a few years ago and have been building on ever since. I've been wanting to add some AJAX functionality to it using the new CFAJAX feature of CF8.
I went to learncf.com and downloded their tutorial. It runs perfectly, and I used it as a model for what I've written.
I have two instances here with the same problem. First, I try to pass the value #userid# via my JS call to the AJAX instance, because the system does a check to see if there are any private messages waiting.
In the second case, I'm passing #threadid# because I'm using it to quickly subscribe/unsubscribe while viewing a thread.
In both cases, the CFC never receives the value. It's always zero. I got the first one to work by referencing #cookie.userid# in the CFC, although I know that's not good programming practice. At least I know the CFC and the AJAX call works.
I've made sure I spelled things right... there are no case-sensitivity issues in the variable names, etc. I've done View Source on the rendered page to ensure the value is there. I've put an Alert() function in the AJAX call just before it makes the call, to ensure the value is still there. It is. I've put CFLOGs in the CFC to see what arguments.userid or arguments.thread id is, and it's zero. I've even logged a CFDUMP and it's zero in that too.
Next, I used Firebug (addon to Firefox for those who don't know what it is -- VERY slick) to watch the actual call take place. The value gets passed, as I see this:
http://www.sitename.com/ajax/thread.cfc?method=unSubThread&returnFormat=json&argumentCollection=%7B%22threadid%22%3A44841%7D&_cf_nodebug=true&_cf_nocache=true&_cf_clientid=4101F466737A8C82EFF3B56EFE433C0A&_cf_rc=1
And I get this back:
_cf_clientid 4101F466737A8C82EFF3B56EFE 433C0A
_cf_nocache true
_cf_nodebug true
_cf_rc 1
argumentCollection {"threadid":44841}
method unSubThread
returnFormat json
So it's getting the proper value, but for some reason, the CFC is blind to it.
I thought maybe I had a unique bug on my server setup (Win2k3, CF8 with Hotfix 2), but then I thought about the learncf.com tutorial. One of the two pieces of that tutorial passes a parameter to its proxy.cfc and it works just fine. So instead, something else must be weird.
I went to learncf.com and downloded their tutorial. It runs perfectly, and I used it as a model for what I've written.
I have two instances here with the same problem. First, I try to pass the value #userid# via my JS call to the AJAX instance, because the system does a check to see if there are any private messages waiting.
In the second case, I'm passing #threadid# because I'm using it to quickly subscribe/unsubscribe while viewing a thread.
In both cases, the CFC never receives the value. It's always zero. I got the first one to work by referencing #cookie.userid# in the CFC, although I know that's not good programming practice. At least I know the CFC and the AJAX call works.
I've made sure I spelled things right... there are no case-sensitivity issues in the variable names, etc. I've done View Source on the rendered page to ensure the value is there. I've put an Alert() function in the AJAX call just before it makes the call, to ensure the value is still there. It is. I've put CFLOGs in the CFC to see what arguments.userid or arguments.thread id is, and it's zero. I've even logged a CFDUMP and it's zero in that too.
Next, I used Firebug (addon to Firefox for those who don't know what it is -- VERY slick) to watch the actual call take place. The value gets passed, as I see this:
http://www.sitename.com/ajax/thread.cfc?method=unSubThread&returnFormat=json&argumentCollection=%7B%22threadid%22%3A44841%7D&_cf_nodebug=true&_cf_nocache=true&_cf_clientid=4101F466737A8C82EFF3B56EFE433C0A&_cf_rc=1
And I get this back:
_cf_clientid 4101F466737A8C82EFF3B56EFE
_cf_nocache true
_cf_nodebug true
_cf_rc 1
argumentCollection {"threadid":44841}
method unSubThread
returnFormat json
So it's getting the proper value, but for some reason, the CFC is blind to it.
I thought maybe I had a unique bug on my server setup (Win2k3, CF8 with Hotfix 2), but then I thought about the learncf.com tutorial. One of the two pieces of that tutorial passes a parameter to its proxy.cfc and it works just fine. So instead, something else must be weird.
ASKER
Here's the JS code that creates the proxy... I can paste in the cfc in the next post if needed.
The values below (userid and threadid) are both valid CF variablenames. I pasted in the call to pmCount at the bottom, and then the call to the subUnsub routines below that. In the case of #threadid# below, that value is coming out of a query (e.g. cfoutput query="whatever").
The values below (userid and threadid) are both valid CF variablenames. I pasted in the call to pmCount at the bottom, and then the call to the subUnsub routines below that. In the case of #threadid# below, that value is coming out of a query (e.g. cfoutput query="whatever").
<script language="JavaScript">
function do_subThread(threadid) {
var instance = new thread_proxy();
instance.setCallbackHandler(subUnsubCountSuccess);
instance.subThread(threadid);
}
function do_unSubThread(threadid) {
var instance = new thread_proxy();
instance.setCallbackHandler(subUnsubCountSuccess);
instance.unSubThread(threadid);
}
function subUnsubCountSuccess(result) {
document.getElementById('subunsub').innerHTML = result;
}
function pmCount(userid) {
var userid = userid;
var instance = new pm_proxy();
instance.setCallbackHandler(pmCountSuccess);
instance.countPM(userid);
}
function pmCountSuccess(result) {
document.getElementById('pm_count').innerHTML = result;
}
</script>
<script language="javascript">
<cfoutput>
pmCount(#cookie.userid#);
</cfoutput>
</script>
<cfoutput>
<A HREF="##" onClick="do_subThread(#threadid#);" class="smalltext"><b>Subscribe</b></A>
<A HREF="##" onClick="do_unSubThread(#threadid#);" class="smalltext"><b>Unsubscribe</b></A>
</cfoutput>
Ok so ColdFusion variables evaluate at run time.
So, I reckon that you are creating the threadid variable after this javascript code. Thus you have the script stuff at the top in your header and the variable does not have a value at that point.
Is that correct, does threadid exist, is there a <cfset thredid = somewhere above this javascript.
That would also explain why the cookie one works as cookies get created on previous page, thus it's already there.
So, I reckon that you are creating the threadid variable after this javascript code. Thus you have the script stuff at the top in your header and the variable does not have a value at that point.
Is that correct, does threadid exist, is there a <cfset thredid = somewhere above this javascript.
That would also explain why the cookie one works as cookies get created on previous page, thus it's already there.
ASKER
Hmmm.... interesting point.
Yes, the block of JS code exists right at the top, just inside by <body> tag. The threadid value happens later, inside a cfoutput query="whatever" tag.
BUT... the function call (e.g. do_unsub) does pass the value... i.e. if I View Source, I will see "do_unsub(44681)" or whatever the actual threadid was.
Likewise, if I put an alert(threadid); in the actual do_unsub() function, just before it calls the ajax instance, it will come up with the proper value.
Make sense?
Here's a related question... request values. Inside my CFC, I refer to my dsn as #request.dsn#. This works fine. I put cfset request.threadid = threadid inside my cfoutput loop in the hopes of just referencing request.threadid inside the CFC (just as I did with cookie.userid) but that failed. Maybe this is related to what you're talking about -- the order in which stuff is being defined.
Yes, the block of JS code exists right at the top, just inside by <body> tag. The threadid value happens later, inside a cfoutput query="whatever" tag.
BUT... the function call (e.g. do_unsub) does pass the value... i.e. if I View Source, I will see "do_unsub(44681)" or whatever the actual threadid was.
Likewise, if I put an alert(threadid); in the actual do_unsub() function, just before it calls the ajax instance, it will come up with the proper value.
Make sense?
Here's a related question... request values. Inside my CFC, I refer to my dsn as #request.dsn#. This works fine. I put cfset request.threadid = threadid inside my cfoutput loop in the hopes of just referencing request.threadid inside the CFC (just as I did with cookie.userid) but that failed. Maybe this is related to what you're talking about -- the order in which stuff is being defined.
No, if the stuff is in the alert and view source then it's working fine.
Perhaps the problem lies in the cfc.
Perhaps the problem lies in the cfc.
ASKER
Here's the CFC in case you can see anything weird in it. This is just the thread.cfc (the one that deals with threadid).
<cfcomponent>
<cffunction name="subThread" access="remote" returntype="string">
<cfargument name="threadid" type="numeric" required="true" />
<cfset threadid = arguments.threadid>
<!--- <cflog text="threadid = #threadid# (sub)." file="thread-ajax-cfc"> --->
<cfsavecontent variable="result">
<cfoutput>
<A HREF="##" onClick="do_unSubThread(#threadid#);"><b>Unsubscribe</b></A>
</cfoutput>
</cfsavecontent>
<cfif threadid gt 0>
<cftry>
<cfquery name="check_sub" datasource="#request.dsn#">
select id
from threadsubs
where userid = <cfqueryparam value="#cookie.userid#">
and threadid = <cfqueryparam value="#threadid#">
and active = <cfqueryparam value="1">
and siteid = <cfqueryparam value="#request.siteid#">
</cfquery>
<cfif check_sub.recordcount eq 0>
<cfquery name="get_ids" datasource="#request.dsn#">
select threadid, topicid, categoryid
from threads
where threadid = <cfqueryparam value="#threadid#">
and siteid = <cfqueryparam value="#request.siteid#">
</cfquery>
<cfoutput query="get_ids">
<cfquery name="do_sub" datasource="#request.dsn#">
set nocount on
insert into threadsubs (
active,
userid,
threadid,
topicid,
categoryid,
siteid,
date_added
)
values (
<cfqueryparam value="1">,
<cfqueryparam value="#cookie.userid#">,
<cfqueryparam value="#threadid#">,
<cfqueryparam value="#topicid#">,
<cfqueryparam value="#categoryid#">,
<cfqueryparam value="#request.siteid#">,
#CreateODBCDateTime(Now())#
)
set nocount off
</cfquery>
</cfoutput>
</cfif>
<cfcatch type="database">
<cfset result = "<b>DB Error</b">
</cfcatch>
</cftry>
<cfelse>
<cfset result = "Error (threadid is 0)">
</cfif>
<cfreturn result>
</cffunction>
<cffunction name="unSubThread" access="remote" returntype="string">
<cfargument name="threadid" type="numeric" required="true" />
<!--- <cfsavecontent variable="dump">
<cfdump var="#arguments#">
</cfsavecontent>
<cflog text="#dump#" file="thread-ajax-cfc-dump"> --->
<cfset threadid = arguments.threadid>
<!--- <cflog text="threadid = #threadid# (unsub)." file="thread-ajax-cfc"> --->
<cfsavecontent variable="result">
<cfoutput>
<A HREF="##" onClick="do_subThread(#threadid#);" class="smalltext"><b>Subscribe</b></A>
</cfoutput>
</cfsavecontent>
<cfif threadid gt 0>
<cftry>
<cfquery name="do_unsub" datasource="#request.dsn#">
set nocount on
update threadsubs
set active = <cfqueryparam value="0">
where userid = <cfqueryparam value="#cookie.userid#">
and threadid = <cfqueryparam value=" #threadid#">
and siteid = <cfqueryparam value="#request.siteid#">
set nocount off
</cfquery>
<cfcatch type="database">
<cfset result = "<b>DB Error</b">
</cfcatch>
</cftry>
<cfelse>
<cfset result = "Error (threadid is 0)">
</cfif>
<cfreturn result>
</cffunction>
</cfcomponent>
I see you had a log there, is the value getting through to the log.
Try prefixing all the parameters that come from the form with "url."
Ex:
and threadid = <cfqueryparam value=" #url.threadid#">
Ex:
and threadid = <cfqueryparam value=" #url.threadid#">
Call it from a browser, then view source do you get a result
http://www.sitename.com/ajax/thread.cfc?method=unSubThread&threadid44681
Does the view source result have the correct result?
http://www.sitename.com/ajax/thread.cfc?method=unSubThread&threadid44681
Does the view source result have the correct result?
they are not url paramaters, thats a bad idea.
The problem is almost certantly with the CFC. The browsing to that url I posted (with your domain) will confirm that.
you shouldn't be doing <cfset threadId = arguments.threadId />
That is bad, especially since you didn't var the variables. Just use arguments.threadId everywhere.
you shouldn't be doing <cfset threadId = arguments.threadId />
That is bad, especially since you didn't var the variables. Just use arguments.threadId everywhere.
I think I see the problem
<cfif check_sub.recordcount eq 0>
should that be
<cfif check_sub.recordcount neq 0>
Not equal?
<cfif check_sub.recordcount eq 0>
should that be
<cfif check_sub.recordcount neq 0>
Not equal?
Ohh, no sorry that is a sub not an unsub.
ASKER
I tried the (corrected) url... it came back with my error "Error (threadid is 0)".
No, the value never makes it into the log. It too reports 0 every time.
I removed the cfset threadid = argumetns.threadid and replaced all instances with arguments.threadid. Reran it just in case, no change.
No, the value never makes it into the log. It too reports 0 every time.
I removed the cfset threadid = argumetns.threadid and replaced all instances with arguments.threadid. Reran it just in case, no change.
Ok, try this
1. Change the argument type to Any on line 4
Then add this on line 5
<cfdump var="#arguments#" output="c:\path\dump.txt" />
And tell me whats in there.
1. Change the argument type to Any on line 4
Then add this on line 5
<cfdump var="#arguments#" output="c:\path\dump.txt" />
And tell me whats in there.
ASKER
Made the changes, and here's the contents of that dump...
struct
ACTION: stats
ALPHA: a
AVID: 0
CATID: 0
CSID: 0
DAYSBACK: -30
FID: 0
FROMUSERID: 0
GOBACK: [empty string]
LINKID: 0
OLDACTION: [empty string]
PAGE: 1
PHID: 0
PHOTOID: 0
PMID: 0
POSTHIST: -48
POSTID: 0
RSVPID: 0
SHOWDEL: 0
SITE_ID: 0
SPOTID: 0
THREADID: 0
THRID: 0
THUMBS: 0
TOPID: 0
TRY: 0
USERID: 0
VERIFY: 0
_CF_CLIENTID: EC0E3E7C1DEB46799A613046CAC8FA58
_CF_NOCACHE: true
_CF_NODEBUG: true
_CF_RC: 1
Thats a lot of stuff, should just have threadid
I think you are calling this somwhere else with a lot of paramaters.
Is that the result in the dump when you run this from the url method and not your code?
I think you are calling this somwhere else with a lot of paramaters.
Is that the result in the dump when you run this from the url method and not your code?
ASKER
I re-ran it off the URL and got the same results... but fwiw, what you're seeing are a lot of cfparam'd values that I use on the site. Those are all URL values too btw.
Sorry,
That doesn't make any sense. There is no way anything should be in that arguments scope that isn't in that function, so there is something fundamentally wrong with the CFC.
That doesn't make any sense. There is no way anything should be in that arguments scope that isn't in that function, so there is something fundamentally wrong with the CFC.
ASKER
You make another good point. I got to thinking about it and yeah, the CFC should be blind to all external values except what's passed to it, and some request, application and cookie variables, right?
Hmmm.
Rob
Hmmm.
Rob
Correct,
And since you are only dumping the arguments scope there should only be one thing for that function, and that is the threadid.
And since you are only dumping the arguments scope there should only be one thing for that function, and that is the threadid.
I seem to recall that there might be issues with application.cfc in some configs.
Perhaps rename it so that it wont be found and do another test.
Perhaps rename it so that it wont be found and do another test.
ASKER
I'm not using an Application.cfc with this site... just Application.cfm. The codebase itself is largely CF5-based but I've been slowly modifying it to bring it up to more current levels.
Rob
Rob
Ok,
Simple test
change test.cfc to just do this
Then browse to URL
http://www.domain.com/test.cfc?method=subThread&threadid=12345
Then the view source after that should show 12345 and the dump.text should have 12345
If that works, the other cfc is dodgy and this proves it.
Simple test
change test.cfc to just do this
Then browse to URL
http://www.domain.com/test.cfc?method=subThread&threadid=12345
Then the view source after that should show 12345 and the dump.text should have 12345
If that works, the other cfc is dodgy and this proves it.
<cfcomponent>
<cffunction name="subThread" access="remote" returntype="string">
<cfargument name="threadid" type="numeric" required="true" />
<cfdump var="#arguments#" output="C:\path\dump.txt" />
<cfreturn arguments.threadid />
</cffunction>
</cfcomponent>
ASKER
Okay, here's the dump contents in the "code" window... it ran, it received threadid just fine, but there are still other values showing up in the dump. But I did get "12345" in the browser window, which is good news. We're definitely making progress!!!
I just had another idea so I ran another test. I put your test.cfc file in another site's directory (a totally unrelated site to the forum, in fact one that isn't really used for anything), and ran it there. The dump result ONLY showed threadid.
This is my cfapplication tag from the forum site:
<cfapplication name="forum" setclientcookies="no" sessionmanagement="yes">
Could that be causing trouble?
I just had another idea so I ran another test. I put your test.cfc file in another site's directory (a totally unrelated site to the forum, in fact one that isn't really used for anything), and ran it there. The dump result ONLY showed threadid.
This is my cfapplication tag from the forum site:
<cfapplication name="forum" setclientcookies="no" sessionmanagement="yes">
Could that be causing trouble?
struct
ACTION: stats
ALPHA: a
AVID: 0
CATID: 0
CSID: 0
DAYSBACK: -30
FID: 0
FROMUSERID: 0
GOBACK: [empty string]
LINKID: 0
OLDACTION: [empty string]
PAGE: 1
PHID: 0
PHOTOID: 0
PMID: 0
POSTHIST: -48
POSTID: 0
RSVPID: 0
SHOWDEL: 0
SITE_ID: 0
SPOTID: 0
THREADID: 12345
THRID: 0
THUMBS: 0
TOPID: 0
TRY: 0
USERID: 0
VERIFY: 0
ASKER
Also... here's my cfajaxproxy tags... just in case.
<cfajaxproxy cfc="ajax.pm" jsclassname="pm_proxy" />
<cfajaxproxy cfc="ajax.thread" jsclassname="thread_proxy" />
I dont think so, but there might be something else, like an onRequestEnd.cfm or something playing havoc.
Those other details are being injected from somewhere.
Also, make sure you disable template caching in dev, it's possible it's just recompiling and your calling an old version. That setting is in Administrator somewhere.
Simple test to fix that is
rename test.cfc (full version one) to newtest.cfc change your forum to point to that instead in your ajax stuff and as it's new it will recompile.
Those other details are being injected from somewhere.
Also, make sure you disable template caching in dev, it's possible it's just recompiling and your calling an old version. That setting is in Administrator somewhere.
Simple test to fix that is
rename test.cfc (full version one) to newtest.cfc change your forum to point to that instead in your ajax stuff and as it's new it will recompile.
ASKER
I don't have Trusted Cache enabled (not right now anyway)...
But get this... I just put the test.cfc into the cfajaxproxy tag in place of thread.cfc. Then I went to a page and clicked my Subscribe link (which I verified via View Source that it was going to pass a real value), and IT CAME BACK ZERO!! The log confirmed it.
It worked fine when called from the URL in your post above, but when called through the forum code, the value got whacked.
Hmmmmm.... I think we're getting close!
But get this... I just put the test.cfc into the cfajaxproxy tag in place of thread.cfc. Then I went to a page and clicked my Subscribe link (which I verified via View Source that it was going to pass a real value), and IT CAME BACK ZERO!! The log confirmed it.
It worked fine when called from the URL in your post above, but when called through the forum code, the value got whacked.
Hmmmmm.... I think we're getting close!
ASKER
Here's another interesting tidbit... while poking around in general, I came to my browser window where I had run your previous test that you posted a half dozen or so messages back:
http://www.sitename.com/ajax/thread.cfc?method=unSubThread&threadid44681
I noticed that the = sign is missing after threadid.... I didn't realize it then, I just coped & pasted. Well, I put the = sign in, and so now, running from the URL line, MY thread.cfc worked!!
So... it seems the cfc's work when run via URL, but not from within my code...
http://www.sitename.com/ajax/thread.cfc?method=unSubThread&threadid44681
I noticed that the = sign is missing after threadid.... I didn't realize it then, I just coped & pasted. Well, I put the = sign in, and so now, running from the URL line, MY thread.cfc worked!!
So... it seems the cfc's work when run via URL, but not from within my code...
ok, so that's good.
Can you show me the <cfajaxproxy code, perhaps your pointing to the wrong cfc?
Can you show me the <cfajaxproxy code, perhaps your pointing to the wrong cfc?
ASKER
This is what I posted last night...
Definitely pointing to the right CFC... both thread.cfc and pm.cfc live within the ajax/ subdirectory.
Definitely pointing to the right CFC... both thread.cfc and pm.cfc live within the ajax/ subdirectory.
<cfajaxproxy cfc="ajax.pm" jsclassname="pm_proxy" />
<cfajaxproxy cfc="ajax.thread" jsclassname="thread_proxy" />
ASKER
I've been playing with this more... I put your test.cfc in place of my thread.cfc and it only returns 0. If I do it via URL (just like with thread.cfc) it works fine.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
I bet you are passing a variable at the script level that hasn't been created yet. Can you post the code that creates the proxy and the code that calls it, will be easy to fix I think.