ColdFusion - Reference variables in cfloop using query generated from UDF - coldfusion

I'm new to ColdFusion and have an interesting question regarding accessing variables inside a cfloop using a query that is generated from a query function.
I know I can create a variable, assign the result of the query function to the variable, and then loop over the variable containing the query result and access the data using the variable name given to the query attribute inside the loop as follows:
<cfscript>
q = createObject("component", "cfc.myDBquery");
result = q.myQuery();
</cfscript>
<cfloop query="result">
<cfoutput># result.MY_DATA #</cfoutput>
</cfloop>
However, consider this example:
<cfscript>
q = createObject("component", "cfc.myDBquery");
</cfscript>
<cfloop query="#q.myQuery()#">
<cfoutput># ???.MY_DATA #</cfoutput>
</cfloop>
Other than just outputting the data using the column name from the query (e.g. MY_DATA), how would I go about referencing this specific query when outputting data in the loop?
FWIW, Adobe shows this type of scenario in their documentation, however fails to show outputting data inside of the loop using this method:
https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-tags/tags-j-l/cfloop-looping-over-a-query.html
I know I'm being a bit neurotic for trying to eliminate one line from my code, I'm just curious if this is even possible while adhering to best practices.

This is a long formatted comment. Here:
<cfscript>
q = createObject("component", "cfc.myDBquery");
result = q.myQuery();
</cfscript>
Creating the object makes the myQuery() function available. It doesn't actually run it. You might be able to do this:
result = createObject("component", "cfc.myDBquery").myQuery();
Next, since you asked about best practices, don't do this:
<cfloop query="result">
<cfoutput># result.MY_DATA #</cfoutput>
</cfloop>
You are executing the cfoutput tag each time through the loop. Instead, do this:
<cfoutput>
<cfloop query="result">
#result.MY_DATA #
</cfloop>
</cfoutput>
or this
<cfoutput query="result">
#MY_DATA#
</cfoutput>
It behaves like a loop. Other comments about best practices are simply opinions. One of mine is that readable code is good code.

I believe there are 2 possibilities. First, ColdFusion doesn't require the scope when looping over a query so you could just reference the field name you need from the query like so:
<cfloop query="#q.myQuery()#">
<cfoutput>#MY_DATA#</cfoutput>
</cfloop>
Knowing non-scoped variables cause confusion and anger, I believe you can reference the name of the original query from your function call. For instance, if your 'myQuery()' function is something like:
<cffunction name="myQuery">
<cfquery datasource="myDS" name="myQry">
SELECT * FROM Names
</cfquery>
<cfreturn myQry>
</cffunction>
Then your can reference 'myQry' like so:
<cfloop query="#q.myQuery()#">
<cfoutput>#myQry.MY_DATA#</cfoutput>
</cfloop>

Related

ColdFusion cfloop issue

I'm running ColdFusion 2016. I have a cfloop which pulls in data from a query, all other ColdFusion queries work fine on the page and if I pull in the same variable in an output outside the loop, it works fine, except the loop is giving me an error. The error output says:
Variable GPS_LATITUDE is undefined.
Which is correct, as in the database there is no GPS_LATITUDE but there is a GPS_LATITUDE1.
I need to add the loop number on the end of the variable so as it loops pulls in the data gps_latitude1, gps_latitude2, gps_latitude3 not just gps_latitude.
My loop code is...
<cfoutput>
<cfloop index="i" from="1" to="3">
<td><p>#gps_latitude[i]#</p></td>
<td><p>#gps_longitude[i]#</p></td>
</cfloop>
</cfoutput>
Any guidance much appreciated.
#elixieru, You can't directly give gps_latitude[i]. which is not check your query which is consider it as Array. I can imagine your scenario and give my sample code about how to get an same columnName with
<cfquery name='test' datasource="mytest">
select * from test
</cfquery>
This is my sample query. It's having column name as address1, address2 etc... I'm going to get the data about address1 & address2 like your scenario.
<cfloop query="test">
<cfloop from="1" to="2" index="i">
<cfset a = test["address#i#"]>
<cfoutput> #a# </cfoutput> <br/>
</cfloop>
</cfloop>
Here I'm looping over the query and so some simple / index loop based on my count ( Address1,2,3,4,5 etc ). For now I'm just use 2 like from 1 to 2.
Here I've store the test['address#i#'] in variable a and print that variable. Now test['address#i#'] it will consider as test.address1
I hope my sample help you more.

Coldfusion Complex Construct

I am trying to construct a coldfusion conditional statement that looks for incremental form ID checkboxes to have been selected. All checkboxes are defined as Component[component number]. I have established a loop that is looking for a URL variable that is different for every form that calls on the condition as seen below. The issue I am having is that I recieve an error when executing that tells me "Complex constructs are not supported with function parameterexists."
Clearly it has to do with the dynamic nature of the parameterexists statement, but I do not fully know what this means. Can anyone explain this and also offer a solution? I am fairly new to coldfusion and coding, so take it easy on me.
<cfloop from="1" to="#URL.loopcounter#" index="loopvar">
<cfif parameterexists(Form.Component#loopvar#)>
INSERT INTO Results (MP_Barcode, Reworked, Reworked_By)
VALUES ('#Form.MontaplastBarcode#', 'YES', '#URL.BadgeNumber#')
</cfloop>
<cfoutput>
<p class="success">YOUR REWORK HAS BEEN SUBMITTED SUCCESSFULLY.</p>
</cfoutput>
<cfelse>
<p class="error">NO REWORK WAS SUBMITTED. NO COMPONENTS SELECTED.</p>
</cfif>
Depending on the form that calls on this action, the URL loopcounter variable could range from 1 to 50.
To answer the question, there are several ColdFusion functions that won't allow you to create a dynamic name before the function evaluates it. parameterExists() was one of those. Both isDefined() and structKeyExists() will allow dynamic variables. So will the member function of structKeyExists() > structName.keyExists("theKey").
Again, if you are new to ColdFusion, I'd simply pretend you never saw parameterExists(). I believe it has been listed as "deprecated" since CF 4.5 or somewhere around there. That's almost 20 years ago. That function has actually become somewhat of a joke about how Adobe never really throws away their trash.
As I pointed out above, I'd get rid of it completely and go with structKeyExists(). I also don't know what your whole page is doing, but with the code you provided, I'd change it to something like this:
<cfloop from="1" to="#url.loopcounter#" index="loopvar">
<cfoutput>
<cfif structKeyExists(form,"Component#loopvar#")>
<!--- SANITIZE INPUTS --->
<cfset inMontplastBarcode = sanitizingFunction(FORM.MontaplastBarcode)>
<cfset inBadgeNumber = sanitizingFunction(URL.BadgeNumber)>
<!--- Now use sanitized inputs in query with queryparams --->
<cfquery name="InsertStuff" datasource="myds">
INSERT INTO Results (MP_Barcode, Reworked, Reworked_By)
VALUES (
<cfqueryparam value="#inMontaplastBarcode#" cfsqltype="cf_sql_varchar" maxlength="50">
, 'YES'
, <cfqueryparam value="#inBadgeNumber#" cfsqltype="cf_sql_varchar" maxlength="20">
)
</cfquery>
</cfif>
</cfoutput>
</cfloop>
In your database, Reworked should be a boolean datatype. It appears that it may be a 'Yes' or 'No' string. A true boolean will be a) smaller and b) easier to validate. In the cfqueryparams, if you are using a cf_sql_varchar datatype, make sure you set an appropriate max length. You'll need to look at the available CF datatypes and see how they match up to your database datatypes. (Also see https://cfdocs.org/cfqueryparam)
For your sanitizingFunction() that you'll use to sanitize your input variables, you'll want to write a function that will follow through the steps to clean up your variables to strip out unsafe characters or other things you don't want. That is an entirely different, extremely large topic all on its own.
In your form, name your checkboxes simpler. Like reworked01 through reworked50.
On the action page use cfparam to default them to zero (since html forms don't post unchecked boxes):
<cfloop from="1" to="#url.loopCounter#" index="i">
<cfparam name="form.reworked#numberFormat(i, 00)#" default="0">
</cfloop>
Then instead of fumbling with whether or not a variable exists, you can instead look for the value:
<cfloop from="1" to="#url.loopCounter#" index="i">
<cfif evaluate("form.reworked"&i) eq 1>
<!--- some logic here --->
<cfelse>
<!--- some other logic here --->
</cfif>
</cfloop>

<cfif> a value is in an array without looping?

This seems like it should be an easy one, but CF seems to have different ways of accomplishing the same thing when it comes to Arrays, so I want to be sure I'm doing it the best way;
I have a simple cfoutput;
<cfoutput query="getusers">
Username: #username# ID:#fnid#
</cfoutput>
I'm also using cfwebsocket elsewhere on the page, and the value of the 'fnid' (which is a session.auth variable) is part of the subscription. A dump of wsGetSubscribers gives me the following;
What I'd like to do is during the output of the 'getusers' query, check to see if the FNID under subscriberinfo.fndid is there - the goal being to add a note to say that user is subscribed at that point.
I know I can do this using a cfloop, but that seems longwinded!
What I'm trying to avoid is having to use cfloop (on the array) within the cfoutput query
So you want a kind of look-up for fnId? How about:
<cfset subscribersById = StructNew()>
<cfloop array="#wsGetSubscribers()#" index="subsciption">
<cfset subscribersById[subsciption.subscriberInfo.fnId] = subsciption>
</cfloop>
<cfoutput query="getusers">
Username: #username# ID: #fnid# Subscribed: #StructKeyExists(subscribersById, fnid)#
</cfoutput>
CF10+ has arrayEach() as well, if you prefer this syntax over the <cfloop>.

cfml, database and a multilingual website

I have a database that has four columns id,languageid,name,text
Depending on the users' default language, I create a query that has all the texts for the set language (where languageid=#user.defaultlanguageid#)
What's the easiest way of retrieving these when it comes to displaying the required string.
Seems like creating a subquery every time is a bit much work.
Is creating a function the best way to go?
You could just have a single query that populates a struct (perhaps an application-level struct) - something like this:
<cfif not IsDefined("application.langMap")>
<cfquery name="langNames" datasource="...">SELECT * from langTable</cfquery>
<cfset application.langMap = {}>
<cfloop query="langNames">
<cfif not StructKeyExists(application.langMap, languageid)>
<cfset application.langMap[languageid] = {}>
</cfif>
<cfset application.langMap[languageid][name] = text>
</cfloop>
</cfif>
And then as you need the particular string within the display:
#application.langMap[mylanguageid][name]#

cfset problem with adding to existing variable

I am pulling my hair out working on what would seem to be easy problem. But as a ColdFusion rookie I am just having a hell of a time figuring it out.
<cfoutput query="getSeasonAndRate">
<cfset adultRate = groupRate>
</cfoutput>
So ... adultRate = 89
<cfset adultRate = 88>
So why does adultRate STILL equal 89?
Thanks! :D
It could be a scoping issue, try this:
<cfset variables.adultRate= 0>
<cfoutput query="getSeasonAndRate">
<cfset variables.adultRate = getSeasonAndRate.groupRate>
</cfoutput>
<cfdump var="#variables.adultRate#">
It could also be that the query is returning more than one result, trying dumping out what is in that query like this:
<cfdump var="#getSeasonAndRate#">
If your query contains a column named "adultRate" then your CFSET statement is updating the query object, not the variables scope.
This page (disclosure: on my own blog) discusses scope priority when reading and writing variables without explicitly specifying scope.
To fix your problem, change:
<cfset adultRate = groupRate>
to:
<cfset variables.adultRate = getSeasonAndRate.groupRate>
(assuming the groupRate value you want to get the value from is part of the query)