Output list in cfloop with two variables - list

I have following code:
<cfloop from="1" to="3" index="i">
<cfloop list="#FORM.cboStructureLevel_#i##" index="ii" delimiters=",">
#ii#
</cfloop>
</cfloop>
The problem is that I want to output the list but I am getting the error "Element CBOSTRUCTURELEVEL_ is undefined in FORM.". It does not recognize the output of #i# in the list in the second cfloop.
How can I output the whole list as declared above?
Thank you for your help.

Try this for your inner loop:
<cfloop list="#form['cboStructureLevel_' & i]#" index="ii">

try to use evaluate function:
#Evaluate('FORM.cboStructureLevel_#i#')#

Related

cfdirectory loop limit the results

I' am finding it difficult to understand this. How can I limit the results to 50 only. Let say if in the directory I have 1000 files, how can I limit it so that only 50 files are looped over.
<cfdirectory action="list" directory="#ExpandPath('/downloaded/')#" name="listRoot" filter="*.xml" recurse="false" sort="datelastmodified asc">
<cfoutput>
<cfloop query="listRoot" from="1" to="50" index="i">
....
</cfloop>
</cfoutput>
When I run the above code I get the following error message
Attribute validation error for tag CFLOOP.
If you review the complete error message, it contains the answer (emphasis mine):
It has an invalid attribute combination: from,index,query,to. Possible combinations are:
Required attributes: 'query'. Optional attributes: 'endrow,startrow'.
...
Required attributes: 'from,index,to'. Optional attributes: 'step'.
The code is attempting to mix two different types of loops: query loop and from/to loop. That is not a valid combination. You can either use a query loop OR a from/to loop, but not both.
Having said that, since the goal is to display the output, there is really no need for the cfloop. Just use cfoutput with the "startRow" and "maxRows" attributes:
<cfoutput query="listRoot" startRow="1" maxRows="50">
#name#<br>
</cfoutput>
As mentioned in the other answer, recent versions of CF also support for ...in loops:
<cfscript>
for (row in listRoot) {
writeOutput("<br>Debug: name value = "& row.name );
}
</cfscript>
You can access specific rows in a query with:
query[columnName][rowIndex]
In order to do a from to loop instead of an each loop, go:
<cfoutput>
<cfloop from="1" to="50" index="i">
#listRoot["name"][i]#<br>
</cfloop>
</cfoutput>

Checking the structure is existing or not

Here is my array loop which has structures inside that
I am looping over it and i need to skip those fields where the struct is not defined, howver i am getting everytime
Here is my code:
<cfloop index="apos" from=1 to="#arrayLen(myarray)#">
<cfdump var="#myarray[apos].company#">
<cfdump var="#StructKeyExists(myarray[apos].company,'#myarray[apos].company.size#')#">
<cfdump var="#StructFindKey(myarray[apos].company,'myarray[apos].company.size','ALL')#">
</cfloop>
The error is throwing on line 3, where i am getting error: Element COMPANY.SIZE is undefined in a CFML structure referenced as part of an expression.
Although i had tried the structFindvalue, but that does not work, perhaps that is expecting some simple values, so what could be the best possible alternative here
With structKeyExists you want to give that function the struture to look and the key you're looking for, so in myarray[apos].company you want to see if 'size' exists, not the entire structure.
<cfloop index="apos" from=1 to="#arrayLen(myarray)#">
<cfdump var="#myarray[apos].company#">
<cfdump var="#StructKeyExists(myarray[apos].company,'size')#">
</cfloop>

Creating an Insert Statement for mysql table

I am creating a INSERT Starement for my table. Till now all going good and i have been able to create the Insert Statement. Only Issue Left is: It shows a trailing comma after the end of every single record. Can you guys have a look around what mess I am doing here
<cfset listcount = getQueryColumns(insertData)>
<cfset counter = 1>
<cfloop query="insertData">
<cfoutput>
INSERT INTO `mytable` (#listcount#)
VALUES(
<cfloop index="col" list="#listcount#">'#insertData[col][currentRow]#'
<cfif counter LT insertData.recordcount>,</cfif>
</cfloop>);<br><br>
</cfoutput>
<cfset counter++>
</cfloop>
Your error is due to the fact that you are incrementing your counter in the outer loop instead of the inner loop.
I think I've got it. I believe this is what you need:
<cfset listcount = getQueryColumns(insertData)>
<cfloop query="insertData">
<cfset counter = 1>
<cfoutput>
INSERT INTO `mytable` (#listcount#)
VALUES(
<cfloop index="col" list="#listcount#">'#insertData[col][currentRow]#'
<cfif counter LT listcount>,</cfif>
<cfset counter++>
</cfloop>);<br><br>
</cfoutput>
</cfloop>
What I changed is:
As Dan Bracuk pointed out, I moved <cfset counter++> inside the inner loop. I also moved <cfset counter = 1> inside the outer loop, as it will need to be reinitialized through successive INSERT statements.
I changed <cfif counter LT insertData.recordcount> to <cfif counter LT listcount>, as you don't want to iterate over the recordcount (this is why your commas stopped appearing after Priority, which was the 8th field). Instead, you want to iterate over the number of columns.
EDIT: See my more recent answer. I'm leaving this one in place because the comments were useful in the diagnosis.
I think Dan Bracuk is correct about your counter increment. But you might be able to simplify your code and avoid the <cfif > statement entirely if you you use the list attribute in <cfqueryparam >. For example:
<cfqueryparam value="#NAME_OF_LIST#" list="yes" >
By default this will put a comma between your list values before sending them to the database.
Check out the other attributes it takes at http://www.cfquickdocs.com/cf8/#cfqueryparam.

Checking for key existence in structure

I have a variable named #cfData# which contains an array of structures. As it's clear from the image, for 1st structure array there are 6 keys and for 2nd, only two keys,viz date and open.
If I run a common loop, to go through each and every key, I will get an error at second array element. So the following only works when all the keys are present in the structure:
<cfset blockedtotal = 0 />
<cfset bouncetotal = 0 />
<cfset blocked = 0/>
<cfset datetotal = 0 />
<cfloop array = #cfData# index = "i">
<cfset blockedtotal += i.blocked />
<cfset bouncetotal += i.bounce />
</cfloop>
After reading online, I got an idea of using StructKeyExists where I think I can proceed in the following way:
<cfif structKeyExists(cfData,"bounce")>
<cfoutput>Bounce:#cfData.bounce#"/></cfoutput>
<cfelse>
<cfoutput> Bounce : [none]<br/></cfoutput>
</cfif>
But I am wondering, where exactly should I insert the above code inside the cfloop? Please advise if my approach is wrong.
Update:
Thanks guys. I got it running by using the following code based on the answers and it's running fine:
<cfloop array="#cfData#" index="i">
<cfif structKeyExists(i, "date")>
<cfset counter++>
<cfoutput>#counter#</cfoutput> Date is: <cfoutput> #i.date#</cfoutput> <br/>
</cfif>
</cfloop>
you don't need a "common loop". You can loop through each struct with
<cfloop array="#cfData#" index="i">
<cfloop collection="#i#" item="key">
struct with key '#key#' has data: #i[key]#
</cfloop>
</cfloop>
Of, if you need to decide if the struct has certain key, do something:
<cfloop array="#cfData#" index="i">
<cfif structKeyExists(i, "someKey")>
<cfset counter++>
</cfif>
</cfloop>

How To Loop Through Two Lists?

I need to join the output of two separate lists together to output in a CFMAIL, and I'm wondering what the best way to approach this is.
I have two form fields: first_name and last_name
The fields have up to 5 names in each. I need to loop through those names and join the first and last names, then output them to unordered list. I am having trouble visualizing what the right approach to accomplish this is.
Can someone suggest a method in CFML (I don't know CFSCRIPT very well).
Thanks!
EDIT: I should have added that both fields will always have the exact same number of entries. Thanks to all that answered -- proof that there are a lot of ways to skin a cat :)
I would do something like
<cfloop from="1" to="#ListLen(firstnames)#" index="i">
#ListGetAt(firstnames,i)# #ListGetAt(lastnames,i)#<br>
</cfloop>
If this were a list of 5000 you would be better off putting it in a structure or an array, but for a list of ~5 this should be sufficient.
I think this would be the easiest way to accomplish this.
<!--- Create a names container --->
<cfset names = "<ul>">
<!--- Fill some dummy containers --->
<cfset first = "thomas,henry,philip,john,rony">
<cfset last = "smith,baker,crowe,ryan,jones">
<!--- Loop through the lists and append them to the container string --->
<cfloop index="name" to="#listLen(first)#" from="1">
<cfset names &= "<li>" & ListGetAt(first,name) & " " & ListGetAt(last,name) & "</li>">
</cfloop>
<cfset names &= "</ul>">
<cfoutput>#names#</cfoutput>
I would add in a check to make sure that your list values exists at each index, otherwise you will get errors. I would also add in a check to loop through whichever list is greater so that you get all values just in case someone doesn't enter exactly 5 in both:
<Cfset firstnames="Matt,Ian,Brandon,Sam,Tom">
<cfset lastnames="Jones,Smith,Weiss">
<!--- SEE WHICH LIST IS LONGER AND SET THAT AS THE ONE THAT WE WILL USE FOR THE LOOP --->
<cfif ListLen(firstnames) gte ListLen(lastnames)>
<cfset primary=firstnames>
<cfelse>
<cfset primary=lastnames>
</cfif>
<cfset myOutput="<ul>">
<cfloop from="1" to="#ListLen(primary)#" index="i">
<Cfset myOutput &= "<li>">
<cfif ListLen(firstnames) gte i>
<cfset myOutput &= ListGetAt(firstnames,i)>
</cfif>
<cfif ListLen(lastnames) gte i>
<cfset myOutput &= " " & ListGetAt(lastnames,i)>
</cfif>
<Cfset myOutput &= "</li>">
</cfloop>
<Cfset myOutput &= "</ul>">
<cfoutput>#myOutput#</cfoutput>
You could use the "list" attribute with CFLOOP although it means combining list functions within the output. Here is an example though of how it could be done and it makes the assumption the two lists will always have the same lengths. If these names are keyed in by users then I might be afraid of if they put in a comma since that would throw things off with any sort of looping.
<cfset lstFirstNames = "John,Bob,Tom,Jeff" />
<cfset lstLastNames = "Smith,Doe,Rodriguez,Horan" />
<cfloop list="#Variables.lstFirstNames#" index="FirstName" />
#FirstName# #ListGetAt(Variables.LastNames, ListFind(Variables.lstFirstNames, FirstName))#<br />
</cfloop>
try:
<cfset lstFirstNames = "John,Bob,Tom,Jeff" />
<cfset lstLastNames = "Smith,Doe,Rodriguez,Horan" />
<cfloop list="#Variables.lstFirstNames#" index="FirstName">
<cfoutput>#FirstName# #ListGetAt(Variables.lstLastNames, ListFind(Variables.lstFirstNames, FirstName))#</cfoutput><br />
</cfloop>