Coldfusion Multi-Select box without CFSelect - coldfusion

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>

Related

How to perform submit button function in ColdFusion?

I am new to coldfusion ,
please check my code below
<cfif isDefined("form.submit")>
<cfoutput>
<h3>hi</h3>
</cfoutput>
</cfif>
<cfform action="#CGI.SCRIPT_NAME#">
User Name:<cfinput type="Text" name="usr_nm"><br>
<cfinput type="Radio" name="access_flg" value="0">Admin
<cfinput type="Radio" name="access_flg" value="1">User</br>
<cfinput type="submit" name="submit" value="submit"><br>
</cfform>
But ,When I am clicking submit button ,I am expecting result as hi
I haven't see hi message, Is there any thing wrong in my code ,Any one please help me
Since you're new to ColdFusion, I'll give you some advice straight away:
1. Do not submit a form to the same page.
Submit the form to a separate page for processing. Reason being, as you get into more advanced applications, you'll need to restrict pages/URLs to only respond to an appropriate HTML Verb.
Your form page should respond to HTTP GET.
Your form processing page should only respond to HTTP POST.
2. Do not use CFFORM.
The function of CFFORM is to create JavaScript validation and server-side interactions. This can easily be done with modern JavaScript libraries like
https://jquery.com/
http://jqueryvalidation.org/
3. Give your form elements an ID, as well as a NAME.
This allows easier reference to the form elements when using JavaScript.
4. Do not name your submit button "submit".
If you ever want to use JavaScript to submit a form, the function is submit().
For example: $('#myForm').submit();
Having a form element named the same as a function will cause errors.
Here's my_form.cfm:
<form id="myForm" name="myForm" action="my_form_action.cfm" method="post">
User Name:<input type="Text" id="usr_nm" name="usr_nm"><br>
<input type="Radio" id="access_flg_0" name="access_flg" value="0">Admin
<input type="Radio" id="access_flg_1" name="access_flg" value="1">User</br>
<input type="submit" id="my_form_submit" name="my_form_submit" value="Submit"><br>
</form>
5. You don't need to use CFOUTPUT unless you are rendering data from the server.
Here's my_form_action.cfm:
<cfif structKeyExists(form, "my_form_submit")>
<h3>Hi!<lt>
</cfif>
Even better:
<cfif (cgi.request_method IS "post") AND (structKeyExists(form, "my_form_submit"))>
<h3>Hi!<lt>
</cfif>
This is an elaboration of this part of Adrian's answer:
<cfif (cgi.request_method IS "post") AND (structKeyExists form, "my_form_submit"))>
<h3>Hi!</h3>
</cfif>
This is a candidate for code re-use. In one of our applications, I wrote a custom tag that does something like this:
if (StructKeyExists(attributes, 'ScopeToCheck') is false)
attributes.ScopeToCheck = "form";
if (StructKeyExists(caller, attributes.ScopeToCheck) is false)
Redirect = true;
else if (StructIsEmpty(caller[attributes.ScopeToCheck]) is true)
Redirect = true;
else
Redirect = false;
if (Redirect == true)
location(somewhere, false);
The custom tag approach was appropriate for my situation. For other situations, the same logic can be put into a udf that returns either true or false. Then the calling page can decide what to do with that information.

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.

Login System in ColdFusion 9

I am working with a very old login system that my company used before on a website that used frames.
Before, when someone tried a wrong user/pass combination the frame would load a simple cfinclude file with the login form and an error message on top of it.
Now I am using a form in a popup window that calls the application.cfc but instead of getting the error message back on my popup window the page load the cfinclude file from the application component to a new page.
So I need a few things to happen for this application. First, I need the initial popup window to stay up and the page should not submit if the combination of user/pass is wrong, and finally I need the error message to appear somewhere on the popup.
If anyone did something like this before I would really appreciate your feedback.
This is a partial of my code:
Login Form:
<!--- loginErrMsg display - to tell why login is denied --->
<cfif isdefined("loginErrMsg")><span style="color:red">#loginErrMsg#</span><br /></cfif>
<form name="LoginForm" id="LoginForm" action="<cfif test is false>https://secure.example.com</cfif>#loginFormAction#" method="post" target="_top">
</cfoutput>
<input type="hidden" name="loginPost" value="true">
<p>
Login below to take advantage of the great services we offer:
</p>
E-mail:<input name="j_username" class="loginform" type="text" size="30" maxlength="50" id="j_username">
Password: <input name="j_password" type="password" size="30" maxlength="16" class="loginform">
<br />
<input type="submit" name="btn" value="Submit" class="bluebuttonnormal">
</form>
Application.cfc Code:
<cflogin applicationtoken="swmadmin">
<cfif NOT IsDefined("cflogin")>
<cfinclude template="login.cfm">
<cfabort>
<cfelse>
<cfquery name="userlookup" datasource="#ds#">
SELECT clientadminID, roles, isFaxOnly, acctEnabled FROM clientadmin
WHERE
username=<cfqueryparam value="#cflogin.name#" CFSQLTYPE="CF_SQL_VARCHAR" maxlength="50">
and password=<cfqueryparam value="#cflogin.password#" CFSQLTYPE="CF_SQL_VARCHAR" maxlength="16">
</cfquery>
<cfif userlookup.recordcount eq 0>
<cfset loginErrMsg = "Invalid login.">
<cfinclude template="login.cfm">
<cfabort>
</cflogin>
I am working with a very old login system that my company used before
on a website that used frames.
If this is a new website, don't use it. Login forms are a dime a dozen and can be done in your sleep. Start fresh and do it right.
So I need a few things to happen for this application. First, I need
the initial popup window to stay up and the page should not submit if
the combination of user/pass is wrong, and finally I need the error
message to appear somewhere on the popup.
You're going to want to use an AJAX solution here, either write your own or use a good library like jQuery. Once you check the login values you can use jQuery or simple javascript to unhide or update the innerHTML of an empty element to display your error message.
<cflogin ...>
...
</cflogin>
CFLogin makes me sad. Another one of ColdFusion's tags meant to simplify something commonly done that doesn't really help much and sacrifices flexibility. You can get far more control over your application without it. instead of CFLogin, try something like this pseudo code
<cfcomponent>
<cffunction name = "onRequest" ...>
<cfargument name="targetPage" type="String" required = "true" />
<cfif !structKeyExists(session, "roles") and !findNoCase("loginHandler.cfm",cgi.script_name)>
<!--- notice I prevent the redirect on the form handler, otherwise the ajax will get redirected to the login.cfm page --->
<cfinclude template = "login.cfm">
<cfelse>
<cfinclude template = "#arguments.targetPage#">
</cfif>
</cffunction>
</cfcomponent>
Your login.cfm would then contain your form but your button would fire something like jQuery.post() to "loginHandler.cfm", then depending on the result of the login, your callback function may use jQuery.html() to display the error or window.location.replace / window.location.href if the login was successful. Of course, in the event of a successful login, your ColdFusion page would have to create their session variables and do whatever else you want it to do before sending the result back to your AJAX call.

Binding a CFC to cfselect box

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;

CFWheels - DeObfuscate ID on query paging?

I am obfuscating URL's in my app (which is great), but I'd like to disable this for pagination URL's because I'd like the user to be able to enter whatever number they like.
Settings.cfm:
<cfset set(obfuscateURLs = true) />
Home.cfc (controller):
<cffunction name="home">
<cfparam name="params.page" default="1" />
<cfset linkList = model("link").findAll(
select="linkTitle,linkPoints,linkID,linkAuthority,linkCreated,linkUpVoteCount,linkDownVoteCount,linkCommentCount,userName,userID",
include="user",
order="linkPoints DESC",
handle="linkListPaging",
page=params.page,
perPage=5
) />
</cffunction>
Home.cfm (view)
<ul class="pagination">
<cfoutput>
#paginationLinks(
route="paginateLatest",
handle="linkListPaging",
page=1,
name="page",
windowSize=5,
prependToPage="<li>",
appendToPage="</li>",
classForCurrent="current"
)#
</cfoutput>
</ul>
Can I do DeObfuscate on an as needed basis?
Thanks,
Michael
The setting to obfuscate params is an all-or-nothing deal. Just as you can't override this behavior for linkTo(), you cannot override it for paginationLinks() either.
I would suggest building a plugin as I bet there will be other developers out there who would want this in the future. There may be a way to tell the controller to not obfuscate/deobfuscate a parameter named page. You would need to update both how urlFor() works as well as how the controller deobfuscates as it handles incoming requests. You may also consider providing a configuration option to use set() to "blacklist" a set of params keys to never be obfuscated (with page being a default).