CFSelect not binding but text box is - coldfusion

I am using CF10. I have a Select:
<cfselect name="company" id="company" query="qcompany" display="placename" value="placeid" queryposition="below">
<option value="0">--Select--
</cfselect>
I have another cfselect that is bound to the first:
<cfselect name="People" bind="cfc:schedule.GetPeopleArray({company})" ></cfselect>
I cannot get the second cfselect to display any results. To test whether or not I am receiving data from my component (which I will display at the bottom), I bound a text box:
<cfinput name="test" bind="cfc:schedule.GetPeopleArray({company})" bindonload="false"/>
This text box is displaying the results of the call to my component every time, but the cfselect never displays anything.
What could I possibly be doing wrong?
I have tried returning arrays and queries from my component. No help. I have tried adding display and value attributes to the second cfselect. No help.
Here is my component:
<cfcomponent output="false">
<cffunction name="GetPeopleArray" access="remote" returnType="array" output="false">
<cfargument name="company" type="string" >
<!--- Define variables --->
<cfset var data="">
<cfset var result=ArrayNew(2)>
<cfset var i=0>
<cfquery name="qEmployee" datasource="texas" >
SELECT 0 as personid,'Select Person' as fullname,0 as sortorder
UNION
SELECT p.personid ,concat(firstname,' ',lastname) as fullname,3 as sortorder
FROM person p
INNER JOIN placeperson pp
ON p.personid=pp.personid
where personstatus='ACT'
and pp.placeid=#arguments.company#
order by sortorder,fullname
</cfquery>
<!--- Convert results to array --->
<cfloop index="i" from="1" to="#qEmployee.RecordCount#">
<cfset result[i][1]=qEmployee.personid[i]>
<cfset result[i][2]=qEmployee.fullname[i]>
</cfloop>
<!--- And return it --->
<cfreturn result>
</cffunction>
</cfcomponent>

Ultimately, you may want use jQuery anyway, but FWIW your existing code worked fine with CF10. (The only change was removing the JOIN for simplicity) So either you are using different code, or there is something else going on we are unaware of ..
Truthfully the Ajax functionality does have some "quirks". However, you should not have any problem with a simple case like this. Aside from adding a text field, what other debugging or troubleshooting steps did you perform? What I usually recommend is:
Test the CFC independently first. Access it directly in your browser with a variety of sample values:
http://localhost/path/to/schedule.cfc?method=GetPeopleArray&company=someValue
I did this with the original code and discovered an error occurred when the company value is not numeric, like an empty string. (I suspect that might have been the problem) You can prevent that error by substituting an invalid ID like 0 instead. Note, be sure to use cfqueryparam to prevent sql injection.
AND pp.placeid = <cfqueryparam value="#val(arguments.company)#"
cfsqltype="cf_sql_integer">
Enable the CF AJAX debugger in the CF Administrator. Then append ?cfdebug to your test script so you can view the console and check for problems/errors.
http://localhost/path/to/yourTestForm.cfm?cfdebug
Again, I did this after tweaking the query. But there were no errors. Your existing cfform code worked perfectly.
Usually those two steps are enough to pinpoint any problems. If not, make sure your Application.cfc file (if you are using one) is not interfering with the Ajax request. That is a common gotcha. Test the code in a separate directory that is outside any Application files.
EDIT: Also, you may as well set bindonload="false" for the select list too. Since you do not want to call the function when the page first loads. Only when the user selects something from the list.

Related

CFGRID bind in HTML format does not work in Coldfusion 11

OK, so I've spent the last couple of days researching this issue on various websites including this one and I'm still no closer to having an answer. I have seen claims that this was a bug and was fixed on Adobe's end in one of the CF11 patches and I have even seen one answer that claimed that Adobe was emailing the fix directly to individuals - though no information on how to go about getting Adobe to do that was provided on that webpage.
We just updated our intranet to Coldfusion 11 and pages that have a cfgrid using the HTML format and bind data from a cfc no longer show the cfgrid on the page. Other pages that use the Flash format with cfgrid (which apparently can't use the bind attribute with Flash) do work. These HTML cfgrid pages were working properly in Coldfusion 9 before we migrated to 11.
I have simplified the code as much as I can to eliminate other error possibilities - i.e. I've stripped out formatting and am pulling only a couple columns from the database. Here is the code I am currently working on in my dev sandbox:
<cfgrid format="html"
name="userGrid"
bind="cfc:editorFunc.getGridData({cfgridpage},{cfgridpagesize},{cfgridsortcolumn},{cfgridsortdirection})"
pagesize="20">
<cfgridcolumn name="REGION" header="Region">
<cfgridcolumn name="managmentArea" header="Management Area">
</cfgrid>
Here is the code in the cfc (the query does produce results when dumped to the page):
<cffunction name="getGridData" access="remote">
<cfargument name="page">
<cfargument name="pageSize">
<cfargument name="gridsortcolumn">
<cfargument name="gridsortdir">
<cfquery name="records" datasource="webData">
SELECT REGION, managmentArea
FROM areaDesc
ORDER BY Region ASC
</cfquery>
<cfset result = queryConvertForGrid(duplicate(records), arguments.page, arguments.pagesize)>
<cfreturn result>
</cffunction>
Has anyone had any luck getting a cfgrid like this to work in CF11? I could try a JQuery solution like JGrid, however I would prefer to figure out the existing issue with this code if possible.
Any help is much appreciated.
Add this..
<cfif not len(trim(arguments.gridsortcolumn))>
<cfset arguments.gridsortcolumn = "REGION">
<cfset arguments.gridsortdir = "desc">
</cfif>
query....
ORDER BY #arguments.gridsortcolumn# #arguments.gridsortdir#

ColdFusion Component Not Returning Query

I have tried, off and on, for about 6 months or so to figure out CFC's but never could get it. So now I have SQL and LDAP queries scattered around in different pages that I would like to consolidate into a component. The query below works in it's own CF page, (I've omitted some of the query details for the post) but I'm getting a blank page instead of any results. This is my queries.cfc:
<cfcomponent>
<cffunction name="EmployeeQuery" access="public" returntype="query">
<cfargument name="EmployeeID" required="yes" type="string">
<cfldap action = "query"
name = "EmployeeAdd"
attributes = "distinguishedName, displayName"
filter = "sAMAccountName=#Arguments.EmployeeID#"
start = ""
scope="SUBTREE"
maxrows="1"
server = ""
username=""
password=""
separator=";" />
<cfreturn EmployeeAdd>
</cffunction>
</cfcomponent>
I've got a simple entry form where I enter text, click submit, and on the action page I have:
<cfif IsDefined("form.btnEmployeeAdd")>
<cfinvoke component="queries"
method="EmployeeQuery"
cfinvokeargument
name="EmployeeID"
value="#form.txtEmployeeID#">
<h3>Confirm Employee Entered</h3>
<cfoutput>#EmployeeAdd.displayName#</cfoutput>
</cfif>
My result is a blank page, I don't even get the h3 text. As mentioned, all this works fine in .cfm pages, but it craps the bed when I try to put it in a .cfc. As with all documentation on this, there's so many different ways to do this, but nothing I've tried works so I was hoping I could get a push in the right direction.
Your cfinvoke is missing a returnVariable
<cfinvoke component="queries" method="EmployeeQuery" returnVariable="EmployeeAdd">
<cfinvokeargument name="EmployeeID" value="#form.txtEmployeeID#">
</cfinvoke>
<h3>Confirm Employee Entered</h3>
<cfoutput>#EmployeeAdd.displayName#</cfoutput>
Alternatively if you're on CF10 or higher you could do this instead of your cfinvoke
<cfset employeeAdd = new queries().EmployeeQuery(form.txtEmployeeID)>
Looking at your code to invoke the cfc method, it seems like you are doing it in a wrong way. You have added cfinvokeargument inside cfinvoke as an attribute. cfinvokeargument should be added to cfinvoke body, instead. And as #matt suggested you need to add returnvariable attribute to cfinvoke in order to get results returned from the method. Like this.
<cfinvoke component="queries" method="EmployeeQuery" returnVariable="EmployeeAdd">
<cfinvokeargument name="EmployeeID" value="#form.txtEmployeeID#">
</cfinvoke>
Also as #matt suggested, if you are using cf10 or higher you can use new to instantiate the cfc and then call the method using . notation. Like this.
<cfset employeeAdd = new queries().EmployeeQuery(form.txtEmployeeID)>

Pass queried parameters to ColdFusion file multiple times?

I have an cfmail function set-up in a particular file, email_output.cfm, which requires an ID passed to it to work properly, like email_output.cfm?ID=1. I want to set up a cron job that runs through a query returning the various needed IDs to pass. In testing, I can do the following:
<cflocation url="email_output.cfm?ID=10" >
But, since cflocation stops all other execution and opens another page, I can't loop through it. How would I pass parameters from a query to a single CF page multiple times?
Thanks - Joe
A custom tag sample implementation of this...
If this is your first time using a custom tag, it's easiest to put it in the same folder as the page calling it. There are a few options for putting it in a different directory, but let's start simple.
EmailMembers.cfm
<cfquery name="GetUIDs">
select userid from users
</cfquery>
<cfoutput query="GetUIDs">
<cf_maileach uid="#userID#">
</cfoutput>
Notice how I called my tag cf_maileach?
In the same directory, place maileach.cfm, see how the names match?
maileach.cfm
<cfif StructKeyExists(attributes,"uid") and val(attributes.uid) gt 0>
<cfquery name="getinfo">
select fname,lname,email
from users
where userID = <cfqueryparam cfsqltype="cf_sql_integer" value="#attributes.uid#">
</cfquery>
<cfmail to="#getinfo.email#" subject="Hi #getinfo.fname#">...</cfmail>
</cfif>
Notes
Depending on your version of cf, and whether you're using application.cfc or not, there are several ways to place a custom tag in an outside directory. There is also <cfmodule>
This is a sample only, something this basic is redundant, I was just trying to mimic what asker outlined. In this sample, I'm calling a query that could get all the data, only to use it to query row by row.
If you're not familiar with <cfqueryparam>, look it up, use it, love it.
Edit: While a CFHTTP method can serve this purpose, it suffers a few problems
Sessions are not automatically passed (even if the requesting server and destination server are the same.).
The page is accessed like a browser request. Application/OnRequestEnd are processed (and since session info is passed as well, this can cause problems trying to access files in secured areas.
Because of the above, the page would need to be in a folder with its own Application file to negate any application files above it in the directory hierarchy.
To combat 1, 2, and 3, You'd need to code in a layer of security, similar to your application's own security, so that the file is not vulnerable should the url be found.
Each call to the file via cfhttp would need to invoke some extra security checking.
It is significantly slower. In a very simple test with a zero-content application.cfc, the custom tag method was executing in literally <= 1/100th of the time. As actual function is added to the method, the difference in results would change.
Here is some sample code to test this yourself.
Contents of folder "safe":
Application.cfc
[ blank file, to negate my testing site's actual application.cfc ]
Testrun.cfm
<cfoutput><cfset starttick = GetTickCount()>
<cfloop from="1" to="20" index="i">
<cfhttp url="http://mysamesite.com/safe/http.cfm?u=#i#" method="get" result="test">
#test.filecontent#<br>
</cfloop>
CFHTTP Execution Time: #(GetTickCount() - starttick)#<br><br>
<cfset starttick = GetTickCount()>
<cfloop from="1" to="20" index="i">
<cf_testtag u="#i#"><br>
</cfloop>
CustomTag Execution Time: #(GetTickCount() - starttick)#<br><br>
</cfoutput>
testtag.cfm
<cfoutput>The ID entered was #attributes.u#</cfoutput>
http.cfm
<cfoutput>The ID entered was #url.u#</cfoutput>
Results (in milliseconds)
Each test was 20 passes at HTTP and 20 Passes at the custom tag.
CFHTTP Tag
661ms 6ms
1624 5
616 5
460 4
522 6
816 4
You can do this by using cfhttp also
<cfquery name="GetUIDs">
select userid from users
</cfquery>
<cfloop query="GetUIDs">
<cfhttp url="http://localhost:8500/cf10/test.cfm?id=#userid#" method="get" result="test">
</cfloop>

ColdFusion cfautosuggestvalue content is blank, even though a good array is returned from the cfc

I'm working with ColdFusion Server version 8,0,0,176276.
I'm trying to add an autosuggested form field, with asynchronous population through a cfc. I'm using http://www.forta.com/blog/index.cfm/2007/5/31/coldfusion-ajax-tutorial-1-autosuggest for inspiration and syntax.
The autosuggest field works fine if I use a static query (as in Forta's first example). The cfc is successfully returning an array when not used in the form field.
But when I use the cfc for autosuggest, there are no suggestions provided.
I can't see the contents of the input field with "view source," but if I do "inspect element" on the field in Chrome, I can see a div with class="yui-ac-bd" and a ul under it. The list items in the ul are empty when using the cfc, whereas when I use a static query, the list items contain the array members.
Here's the code on my page:
<cfform>
<cfinput type="text" name="JobP"
autosuggest="cfc:autosuggest.AutoSuggest({cfautosuggestvalue})">
</cfform>
And here's autosuggest.cfc:
<cfcomponent output="false" >
<cffunction name="AutoSuggest" access="remote" returntype="array">
<cfargument name="ObjectType" required="false" default="JOBP">
<cfset var result=ArrayNew(1)>
<cfquery name="Objects" datasource="UC4MP">
SELECT oh_name
FROM uc4.oh
WHERE oh_otype = '#ObjectType#'
AND oh_deleteflag = 0
AND oh_lastdate > sysdate - 90
AND oh_client = 1000
and oh_name like 'A%'
ORDER BY oh_name
</cfquery>
<cfloop query="Objects">
<cfset ArrayAppend(result,oh_name)>
</cfloop>
<cfreturn result>
If I put the following code on my page, it outputs the array with the desired contents:
<cfinvoke component="autosuggest" method="AutoSuggest" returnVariable="result">
cfdump var="#result#">
I don't use jQuery yet; most of my Google results for CF autosuggest have involved jQuery and I haven't been able to wade through them for relevance to my problem. Just in case that was going to be your suggestion.
Thank you all for your advice! I had not known there was a separate ajax debugger, the output of which immediately made the problem clear:
info:http: Invoking CFC: /rd/autosuggest.cfc , function: AutoSuggest ,
arguments: {"ObjectType":"A"}
My cfc arguments didn't include the autosuggest itself, so the string passed to the input field was being interpreted as "ObjectType" (the first argument) and used in the query. Since there are no records where oh_otype = 'A', the result was always empty.
I updated my cfc's arguments to
<cfargument name="ObjectType" required="yes" default="JOBP">
<cfargument name="autosuggest" required="yes">
and the invocation to
<cfinput type="text" name="JobP"
autosuggest="cfc:autosuggest.AutoSuggest('JOBP',{cfautosuggestvalue})">
...works perfectly now.
If i remember correctly when I did this some years ago, I had to create a virtual directory in Apacahe and set permisions using the following directives. You can apply the same to IIS if you are working in that environment. That should get it going for you.
Alias /CFIDE "/opt/coldfusion9/wwwroot/CFIDE"
<Directory "/opt/coldfusion9/wwwroot/CFIDE">
allow from all
Options FollowSymLinks
Since then I have been using the typehead javascript from bootstrap 2. Much cleaner and easier to style. You can still use your cfc to call the data and I am including the code to clean it up for typehead.
<cfinvoke component="autosuggest" method="AutoSuggest" returnVariable="result">
<cfset mylist = ArrayToList(result, ",")>
<cfset mylist=ValueList(ShowKey.keyword)>
<cfset mylist = jSStringFormat(#mylist#)>
<input name="keyword" id="keyword" type="text" data-provide="typeahead" data-items="10" data-source='["<cfoutput>#replace(mylist,',','","','ALL')#</cfoutput>"]'/>

Is onApplicationStart is good Idea in ColdFusion?

I have to use a Variable(Query Resultset) in ColdFusion, which will get the results from Other Application DB, and stores in Coldfusion Application.
The main idea is that I need to call the other Application DB only at Server startup time and cache the results in local. And I need to read the variable in other pages in my Application. I won't overwrite that variable in any page.
On googling I found that 'onApplicationStart' is useful to assign the variables at Application Startup time.
Is using the onApplicationStart fine or is there any other way? We can assign a variable at startup time(one time).
If onApplicationStart is fine: how to use? Maybe any link where it is explained clearly is helpful.
Well, it depends. How often will this query data be updated? If it really is unchanging, then onApplicationStart() is a fine place to put it. However, if it will change every so often, you can just tell Coldfusion to cache the query for a certain period of time, then you don't need to mess with onApplicationStart(), but rather when you call the query it will return the cached result automatically (within your specified time period).
Regardless, I would write a custom function to retrieve the data. Then it will be trivial to call it from onApplicationStart() or elsewhere.
Startup.cfc: (Named whatever you like)
<!--- Replace the datasource name with your db name --->
<cffunction name="getStartupQuery" hint="Returns a query recordset for startup">
<cfargument name="datasource" required="no" type="string" default="OtherAppDB">
<!--- Init the query variable --->
<cfset var result = queryNew("id")>
<!-- Get the query dataset --->
<cfquery name="result" datasource="#arguments.datasource#">
YOUR QUERY HERE
</cfquery>
<cfreturn result>
</cffunction>
Application.cfc: (Just the important parts)
<cffunction name="onApplicationStart">
<!--- init the startup.cfc, then retrieve the data
and save it to the application scope. Remember the component name must match
your component above --->
<cfset var startup = createObject("component", "startup")>
<cfset application.varFromOtherDB = startup.getStartupQuery()>
<cfreturn true>
</cffunction>
Now, you should be able to access this variable from any CFM or CFC in your application using:
<cfset myNewVar = application.varFromOtherDB>
or
#application.varFromOtherDB#
IF you use the onApplicationStart() method, I highly recommend implementing a method to reinit the application. For an example, see this other discussion.