Binding a CFC to cfselect box - coldfusion

I am creating a form and for what ever reason, when using a bindOnLoad with a remote CFC, my default value doesn't seem to appear.
Here is the cfselect:
<cfselect name="edcs"
id="edcs"
multiple="false"
bind="cfc:Components.requestSearch.getEDCs()"
bindonload="true"
value="edc_nm"
display="edc_nm">
<option name="">Select an EDC</option>
</cfselect>
And here is the function:
<cffunction name="getEDCs" access="remote" returntype="query">
<cfscript>
var queryService = new Query();
queryService.setDatasource("#APPLICATION.db2system#");
queryService.setName("getEDCs");
queryService.setUserName("#APPLICATION.db2logon#");
queryService.setPassword("#APPLICATION.db2pass#");
queryService.setSQL(
"select distinct rtrim(edc_nm) as edc_nm
from #APPLICATION.db2owner#.pms_account");
var result = queryService.execute();
var edcs = result.getResult();
return("#edcs#");
</cfscript>
</cffunction>
So, when the page loads I see the <option ...> value displayed for a split second and then the list gets populated, and the Select an ECD disappears. I need to have a choice for a null value, which is what the option is for. What am I doing wrong? Thanks.
Addition: According to the CF10 docs, I should be able to use the <option> html tag.
http://help.adobe.com/en_US/ColdFusion/10.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7afe.html

I've run across this issue with CFSELECTs and binding CFCs. I have also been unable to add an <option></option> tag with a bound CFSELECT. The best way would be to create the query and force the result to have the desired input on the top. For example:
SELECT distinct
rtrim(edc_nm) as edc_nm_display,
rtrim(edc_nm) as edc_nm_value
FROM #APPLICATION.db2owner#.pms_account
UNION
SELECT
'Select an EDC' as edc_nm_display,
'0' as edc_nm_value
FROM dual
ORDER BY 2
This will return your query with 'Select an EDC' on the top.
Also, as a check, I believe <option name="">Select an EDC</option> should be <option value="">Select an EDC</option>. I hope that helps.

The query will need to return that value. Try adding it as a UNION statement.

Return is not a function ...
return("#edcs#");
Try changing your function to ...
var result = queryServices().execute().getResult();
return result;

Related

changing the cfselect to normal select

I have a cfselect with bind attribute and the i want to convert that into to the normal select, it also has the onchange attached to it, what kind i do to return it normal jquery or javascript code
here is my code
<cfselect
name="StatusID"
id="StatusID"
bind="cfc:com.getStatus()"
bindonload="True"
value="StatusID"
display="StatusDescription"
selected="#Val(qry.StatusID)#"
data-validation="required"
data-validation-error-msg="Status selection is required."
onChange="CheckActive()" />
for simpler levels, i can do the <select and for the query i can just do a loop over but what about this.
The bind argument on cfselect will invoke that function in your cfc, which will return some result set (Usually json, or a queryobject). That result set will be used to generate the options. Then the "value" attribute specifies which column from the cfc result set will be used in the "value" argument on the resulting "option" elements. likewise, the display argument corresponds to what will be betweeen the options start and end tags. the Selected arugment will determine which option is selected. Ther other arguments pass through to a normal select.
If you want to generate the vanilla select completely on the server side you can do something like this:
<cfscript>
//You can do something like this to get your data from the CFC
//myCom=CreateObject("component","com");
//statuses=myCom.getStatus();
//Since I don't have an example of what your cfc is returning, I'll assume it's a query result set like this
statuses = queryNew("StatusID,StatusDescription","Integer,Varchar",
[
{StatusID=1,StatusDescription="StatusOne"},
{StatusID=2,StatusDescription="StatusTwo"},
{StatusID=3,StatusDescription="StatusThree"}
]);
//also hardcoding this value because I don't have your qry result set
qry = {statusid=2};
</cfscript>
<cfoutput>
<select
name="StatusID"
id="StatusID"
data-validation="required"
data-validation-error-msg="Status selection is required."
onChange="CheckActive()">
<cfloop query="statuses">
<option value="#statuses.StatusID#" <cfif statuses.statusid eq qry.statusid>selected</cfif>>#statuses.StatusDescription#</option>
</cfloop>
</select>
</cfoutput>
If for some reason you actually need to generate the select on the client side via AJAX, then you will need to write some functions in js/jquery that perform the ajax calls to your cfc instead of using the built in bind expression system in coldfusions cfselect. (for example on how to do that see: Calling a CFC function in AJAX/JQuery and Populating selectlist from AJAX call to CFC)
There are also some other libraries that could make this easier like HTMX: https://htmx.org/examples/value-select/

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>"]'/>

CFSelect not binding but text box is

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.

Coldfusion Multi-Select box without CFSelect

How would one go about building a multiselect box in Coldfusion without using CFForm or CFSelect?
This is to pull values from a DB so its not just a static select box it is dynamic.
This is my first time every trying to code in ColdFusion, I have always been a .Net person so this is a bit of a change for me.
The reason why I am needing this is because I've gotten hired into a department at work that uses Coldfusion but from what the Lead developer told me is they do not use CFForm and seeing as how CFSelect requires to be inside CFForm I need a different way of doing this.
Use plain old HTML, for example:
<cfquery name="qryUsers" datasource="datasourcename">
SELECT [User].[UserID], [User].[FirstName]
FROM [User]
</cfquery>
<cfoutput>
<form ...>
<select name="users" multiple="multiple">
<option value="">- please select -</option>
<cfloop query="qryUsers">
<option value="#UserID#">#FirstName#</option>
</cfloop>
</select>
</form>
</cfoutput>

use a startdate on a <cfinput type= "datefield"> in ColdFusion

I am using the <cfinput type="datefield"> and I need to limit the dates that can be chosen. I cannot allow a date that can be selected in the past. Any help here?
Thanks!
Well you have two options validating it strictly server side or additionally adding a client side javascript check.
For the serverside, your cfm processing page could use the DateCompare function like so:
<cfif DateCompare(Date1,Date2) EQUAL -1>
<!--- Date 1 < Date 2 --->
<cfelseif DateCompare(Date1,Date2) EQUAL 0>
<!--- Date 1 = Date 2 --->
<cfelseif DateCompare(Date1,Date2) EQUAL 1>
<!--- Date 1 > Date 2 --->
</cfif>
Documentation and sample code is available for this function at:
http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=functions_m-r_11.html
Another post suggested using the range functionality, however I was not able to get this to work because the Adobe documentation said it was only supported on type numeric.
Alternatively you can use javascript to check if the date is within range live on the page:
<html>
<head>
<script type="text/javascript">
function withinRange(submittedDate) {
var start = Date.parse("08/10/2009");
var end = Date.parse("09/11/2009");
var userDate = Date.parse(document.getElementById('leaveDate').value);
var previousDate = document.getElementById('calendarWorkaround').value;
if (!isNaN(userDate) && ( previousDate != userDate)) {
document.getElementById('calendarWorkaround').value = userDate;
if (start <= userDate && end >= userDate) {
alert("Your date is correct!");
} else {
alert("Date is incorrect.");
}
}
}
</script>
</head>
<body>
<cfform name="testing" id="vacationForm"action="testprocess">
<cfinput name="date" type="datefield" id="leaveDate">
<input type="hidden" name="workaround" id="calendarWorkaround" value="-1">
</cfform>
<!--- To get around onChange bug with cfinput type datefield --->
<cfajaxproxy bind="javaScript:withinRange({leaveDate})">
</body>
</html>
Now I would use the onChange attribute for cfinput on the datefield, however there is a bug that it does not call the javascript function that seems to be documented on a couple of other pages online. The workaround that I used was the cfajaxproxy call with the bind attribute. If you are using cfeclipse, it will give you an error that the syntax is not correct however it worked fine for me.
The hidden input type is necessary because with the cfajaxproxy tag, everytime you click the calendar icon it will call the javascript function which is not what we want. So I store the last value chosen by the user (or -1 on page load) so that the javascript to check if it is within range is only executed if the value changes. It is a bit of a hack, however the implementation of <cfinput type="datefield"> does not work as documented.
You can also modify this example so that coldfusion dynamical generates the start date and end date so it is not hard coded.
Just remember that whichever way you choose, you should always check the value server side just in case the user has javascript disabled.
Try this:
Three datefields.
One is hidden by the hieght = 0. It is your starting point. I used today plus one so the user can select today in the Date Requested field.
<cfformgroup type="horizontal" height="0">
<cfinput type="datefield" name="firstAvailableDate" value="#dateAdd('d', +1,now())#"
</cfformgroup>
The requested date will be only today or before.
<cfformgroup type="horizontal">
<cfinput type="datefield" name="request_date" id="request_date" mask="mm/dd/yyyy" width="100" label=”Date Requested” onFocus="request_date.disabledRanges=[{rangeStart:firstAvailableDate.selectedDate}];" />
The Due Date can only be after the requested date selected.
<cfinput type="datefield" name="datedue" id="datedue" mask="mm/dd/yyyy" width="100" label=”Due Date” onFocus="datedue.disabledRanges=[{rangeEnd:request_date.selectedDate}];" />
</cfformgroup type="horizontal" >
AFAIK, there is no easy way to prevent the client from picking a day in the past. We have fields like that on a few of our forms that we check against the current date on the server side, though. Just remember to generate the date without the time for comparison, or you end up with [today's date] < now().
At first, I thought <cfcalendar> would help, but seems like the startrage and endrange is for disabled range.
I guess if you Really want to limit the range, use something else like jQuery UI Datepicker
Through experimentation, I was able to customize the supporting javascript files to restrict the selectable dates. However the jQuery option sounds good as well.
I just added 100 years on to the endrange attribute for the cfcalendar component, thinking no one will sit and click through that far to beat your validation :
<cfset startRange = #dateformat(now(), 'dd/mm/yyyy')# >
<cfset endRange = dateadd("yyyy", 100, #Now()#)>
<cfset selectedDate = dateadd("d", -1, #Now()#)>
<cfcalendar name="start_period" mask="dd/mm/yyyy" selecteddate="#selectedDate#" startRange="#startRange#" endrange="#endRange#">
Simon.
You can't make a datefield limit the dates that can be chosen. CFINPUT doesn't have any attribute to define this type of rule. You have to go for Jquery datepicker. If you want to use cfinput, you can work around that.
<script language="JavaScript">
$(function() {
$( "#date" ).datepicker({
changeMonth: true,
changeYear: true,
minDate: new Date(1939, 10 - 1, 25),
maxDate: '-1D'
});
});
</script>
<cfinput name="date" type="text" size="30" id="date" >
You should use server side validation as well, but I believe you can use the "range" attribute of cfinput to limit the valid dates.