I need to create a list of country names within quotes and a comma at the end - except the last country name, like this:
(I'm using ColdFusion 10)
"Tuvalu",
"Uganda",
"Ukraine",
"United Arab Emirates",
"United Kingdom",
"Uruguay"
<cfquery name="query_names" datasource="MyDB">
select short_desc
from tbl_country
where NVL(short_desc,' ') <> ' '
order by short_desc
</cfquery>
<cfset TotalRec = "#query_names.Recordcount#">
<cfloop query="query_names">
<cfif query_names.Recordcount GT 271>
<cfoutput>
"#Trim(short_desc)#" & ","
</cfoutput>
<cfelse>
<cfoutput>
"#Trim(short_desc)#"
</cfoutput>
</cfif>
</cfloop>
This loop result in country names within quotes, but no comma. So my loop result in:
"Tuvalu"
"Uganda"
"Ukraine"
"United Arab Emirates"
"United Kingdom"
"Uruguay"
If you really need double quotes, it is probably simpler to append the quoted values to an array and convert it to a list at the end. The ArrayToList function automatically handles the commas for you:
<cfset names = []>
<cfloop query="query_names">
<cfset arrayAppend(names, '"'& short_desc & '"')>
</cfloop>
<cfoutput>#arrayToList(names)#</cfoutput>
Result:
"Tuvalu","Uganda","Ukraine","United Arab Emirates","United Kingdom","Uruguay"
Side note, if single quotes, i.e., ' are acceptable, it is even simpler. Skip the looping and just use QuotedValueList():
<cfoutput>#quotedValueList(query_names.short_desc)#</cfoutput>
Result:
'Tuvalu','Uganda','Ukraine','United Arab Emirates','United Kingdom','Uruguay'
I hope listQualify() does the same in pretty easier way. isn't it???
<cfset myQry = queryNew("country","varchar",[["Tuvalu"],["Uganda"],["Ukraine"],["United Arab Emirates"],["United Kingdom"],["Uruguay"]])>
<cfdump var="#listQualify(valueList(myQry.country),'"')#" />
Also we can use quotedValueList() as Leigh mentioned, if we need single quoted list.
User1557856, you were so close. Your answer is actually good, but for one point. If you correct it, you will get what you want.
The reason why you obtained a list without commas is this:
<cfif query_names.Recordcount GT 271>
This condition is always false apparently. So only the <cfelse></cfif> part of the code is run. That is the part without commas, hence the result.
If you modify your code slightly, as follows, you will get the desired result:
<cfloop query="query_names">
<cfif query_names.currentRow LT query_names.Recordcount>
<cfoutput>
"#Trim(short_desc)#",
</cfoutput>
<cfelse>
<cfoutput>
"#Trim(short_desc)#"
</cfoutput>
</cfif>
</cfloop>
Related
I want to create database location records in mySQL. I have the following html string from a select box:
<cfset x='
<option value="1188">Aka Aka</option><option value="346">Ararimu</option><option value="293">Awhitu</option><option value="2851">Bombay</option><option value="865">Buckland</option>
'>
Rather than manually enter the records in the database, I'd like to strip out the html tags and end up with the following:
Aka Aka
Ararimu
Awhitu
Bombay
Buckland
Then I could do a simple loop based on line breaks and enter the data programatically. I can probably handle that part, but what I need to know is the simplest way to strip out the html to end up with the line break delimited list.
Here you go:
<cfset x='
<option value="1188">Aka Aka</option><option value="346">Ararimu</option><option value="293">Awhitu</option><option value="2851">Bombay</option><option value="865">Buckland</option>
'>
<cfset y = ListToArray(x, "</option>", "false", "true") />
<cfset z = ArrayNew(1) />
<cfloop array="#y#" index="name">
<cfif Trim(ListLast(name, ">")) is not "">
<cfset temp = ArrayAppend(z, ListLast(name, ">")) />
</cfif>
</cfloop>
<cfdump var="#z#" />
you have them in a 'z' array now, you can convert to list and add line break delimiters if you really want to.
The typical way government offices make you record mileage is to enter one number per input box like the example below:
So what I am trying to do is create one input box that can split the session variable into an array. Then when that session variable is split into an array I would like it to set each value in the array to its own session variable.
Mileage Input:
123456 -<cfoutput>#session.checkout.vehicle.mileage#</cfoutput>
array [1,2,3,4,5,6]
6 -<cfoutput>#session.checkout.vehicle.mileage1#</cfoutput>
5 -<cfoutput>#session.checkout.vehicle.mileage2#</cfoutput>
4 -<cfoutput>#session.checkout.vehicle.mileage3#</cfoutput>
3 -<cfoutput>#session.checkout.vehicle.mileage4#</cfoutput>
2 -<cfoutput>#session.checkout.vehicle.mileage5#</cfoutput>
1 -<cfoutput>#session.checkout.vehicle.mileage6#</cfoutput>
So then I will be able to prefill in an already created form that has the boxes split for only one per box.
Where I am super confused and trying to comprehend is that there will not always be 6 variables. Let's say the mileage is 2344. I am assuming it will need to know to start backwards, counting from the right to the left. That's why I started 6 at #session.checkout.vehicle.mileage1#
Hopefully I have not super confused anyone with what I am trying to do. And any help would be greatly appreciated!!
<cfparam name="form.mileage" default="#session.checkout.vehicle.mileage#">
...
<label for="mileage">Mileage:</label>
<input type="text" name="mileage"
id="mileage"
value="<cfoutput>#form.mileage#</cfoutput>">
Edit:
The issue I am having with this is let's say the mileage is 9000 all 0's will not show. (which is great for the first two zero's in (009000) but after the 9 those 0's would still need to show.) Do you any ideas for that issue? Or should this be a new question?
<cfset Mileage = "9000" />
<cfif mileage is not "Exempt">
<cfset Mileage = NumberFormat(trim(Mileage),"000000") />
<cfset MilArray = ReMatch("\d",Mileage) />
<cfelse>
<cfset MilArray = ["E","x","e","m","p","t"]>
</cfif>
<cfdump var="#MilArray#">
<cfif MilArray[1] is not "0">
<!---Section6 First box Odometer Reading--->
<cfpdfformparam name="E" value="#MilArray[1]#">
<cfelse>
<cfpdfformparam name="E" value="">
</cfif>
If I'm understanding, you want to divide the string into six easy to work with variables, or whatever the length of the variable is.
<cfset Mileage = "123456" />
<cfset MilArray = ReMatch("\d",Mileage) />
<cfdump var="#MilArray#" />
You can actually stick a Reverse() in there to reverse the string, this may be handy because you can have [1] at the ones place, [2] at tens, [3] at hundreds.
<cfset Mileage = "123456" />
<cfset MileageR = Reverse(Mileage) />
<cfset MilArray = ReMatch("\d",MileageR) />
<cfdump var="#MilArray#" />
\d by itself in regular expressions just means "one digit". It's the same as [0-9].
As the CFDUMP will show, ReMatch will split your mileage into an easy to work with array. If you use the reverse as above, you can say "The last digit of your mileage is #MilArray[1]#.", as an example.
Edit:
you know the \d ? is there a way to have it be either \d or only the word Exempt? is it possible to create both of those?
There are a few ways.
You can say
<cfif mileage is not "Exempt">
...
<cfelse>
<cfset MilArray = ["Exempt"]>
</cfif>
which creates a one dimensional array populated with "Exempt" as the only element, which might be useful later in your code so you know MilArray is always an array, or you can simply always work with the <cfif mileage is not "Exempt">.
A regex to accomplish the same thing is possible but it achieves the same as the above cfif, and you'd have to write exempt backwards if you're using reverse, like this
<cfset MilArray = ReMatchNoCase("\d|^Exempt$|^tpmexE$)",trim(Mileage)) />
<cfif MilArray[1] is "tpmexE"><cfset milArray = ["Exempt"] /></cfif>
Edit #2:
<cfif isDefined("session") and structKeyExists(session, 'checkout') and structKeyExists(session.checkout, 'info') and structKeyExists(session.checkout.info, 'oreading')>
<cfif isDefined("#MilArray[6]#") eq "">
<cfpdfformparam name="E" value="">
<!---Section6 First box Odometer Reading--->
<cfelse>
<cfpdfformparam name="E" value="#MilArray[6]#">
</cfif>
</cfif>
This is a task for ArrayIsDefined() (link)
<cfif isDefined("session") and structKeyExists(session, 'checkout') and structKeyExists(session.checkout, 'info') and structKeyExists(session.checkout.info, 'oreading')>
<cfset MilArray = ReMatch("\d",session.checkout.info.oreading) />
<cfif not ArrayIsDefined(MilArray,6)>
<cfpdfformparam name="E" value="">
<!---Section6 First box Odometer Reading--->
<cfelse>
<cfpdfformparam name="E" value="#MilArray[6]#">
</cfif>
.... I assume that it continues on down from here... <cfif not ArrayIsDefined(MilArray,5)>........</cfif>
</cfif>
Finally, while there's contention here on whether to use StructKeyExists() over IsDefined(), there's a narrow field where isDefined() fails.
(Don't put structures in the top level and in the variables scope. Cold Fusion gets confused--IE, don't create an object called "variables.form" or "variables.url"). Beyond that, It's mostly just semantics.
Anyway. once you have the above code working (because it's your code and your familiar with it), you might find it useful to switch to the easier to read IsDefined() version, because isDefined can check several levels deep in one condition.
<cfif isDefined("session.checkout.info.oreading')>
<cfset MilArray = ReMatch("\d",session.checkout.info.oreading) />
<cfif not ArrayIsDefined(MilArray,6)>
<cfpdfformparam name="E" value="">
<!---Section6 First box Odometer Reading--->
<cfelse>
<cfpdfformparam name="E" value="#MilArray[6]#">
</cfif>
</cfif>
Edit 3:
Leigh points out
Why so complicated? Can't you just left pad the value with spaces or zeroes? Then change the regex to check for either a digit or space? Then the array will always have six elements
This can be achieved like this:
<cfset Mileage = "exempt" />
<cfif mileage is not "Exempt">
<cfset Mileage = NumberFormat(trim(Mileage),"000000") />
<cfset MilArray = ReMatch("\d",Mileage) />
<cfelse>
<cfset MilArray = ["E","x","e","m","p","t"]>
</cfif>
<cfdump var="#MilArray#">
Which would conveniently drop Exempt into place (handy that it's 6 characters).
You need to do some prechecking before you start generating the pdf to make sure that mileage variable is Exempt or or numeric.
<cfif len((trim(mileage)) gt 6 or not ((isNumeric(trim(mileage))
or mileage is "exempt")>
<!--- The 6 above is a len-check, you may need to update that number to
something else later, but you'll have to put the same number of 0s
in the NumberFormat function.
If you change that number, and the 0s, you'll need to pad the
"Exempt array"... ie ["E","x","e","m","p","t"," "] --->
....raise a flag...
</cfif>
Here is a simpler way.
originalNumber = "123";
sixDigitNumber = right(("000000" & originalNumber), 6);
<cfoutput>
<cfloop from="1" to = "6" index="position">
do something useful with #Mid(sixDigitNumber, position, 1)#
</cfloop>
<cfoutput>
I have a form with many values in it (around 25 fields). After the form is posted and inserted into the database, I have to take the form information and output it to a report. The report should only show fields with those that have values in it (so the report would only have 5 fields in it, if only 5 fields were filled in).
The easiest way would be to do something like this:
<cfif form.firstname neq "">
<li><First Name: #FORM.FIRSTNAME#</li>
</cfif>
<cfif form.lastname neq "">
<li><Last Name: #FORM.LASTNAME#</li>
</cfif>
Can anyone recommend a better way of doing this? I would like to keep it on the ColdFusion side, since the entire report is stripped of HTML to produce a plain text report as well.
You can loop through them like this
<cfloop list="#form.fieldNames#" index="i">
<li><cfoutput>#i# = #form[i]#</cfoutput></li>
</cfloop>
Not sure that is exactly what you want but it might get you on the right track
Based on your comment try this :
<cfloop list="#form.fieldNames#" index="i">
<li><cfoutput>
<cfswitch expression="#i#">
<cfcase value="firstName">
First Name
</cfcase>
<cfcase value="lastName">
Last Name
</cfcase>
<cfdefaultcase>
#i#
</cfdefaultcase>
</cfswitch>
: #form[i]#</cfoutput></li>
</cfloop>
Here's my attempt at this: Thanks to Lance for pointing me towards the right direction:
<ul>
<cfoutput>
<cfloop list="#form.fieldNames#" index="i">
<li>
<cfif len(trim(form[i])) neq 0>
<cfswitch expression="#i#">
<cfcase value="FIRST_NAME">First Name</cfcase>
<cfcase value="LAST_NAME">Last Name</cfcase>
<cfdefaultcase>#i#</cfdefaultcase>
</cfswitch>
: #FORM[i]#
</cfif>
</li>
</cfloop>
</cfoutput>
</ul>
Here's an alternative to using switch/case - put labels in a struct
<cfset FieldLabels =
{ 'first_name' : "First Name"
, 'last_name' : "Last Name"
, 'other stuff' : "Whatever you like"
}/>
<cfoutput>
<ul>
<cfloop index="CurField" list=#Form.FieldNames# >
<cfif len(trim( Form[CurField] )) >
<li>
#StructKeyExists( FieldLabels , lcase(CurField) )
? FieldLabels[ lcase(CurField) ]
: HtmlEditFormat( replace(CurField,'_',' ','all') )
#
: #HtmlEditFormat( Form[CurField] )#
</li>
</cfif>
</cfloop>
</ul>
</cfoutput>
Note that it does not do neq 0 on the len - this is entirely unnecessary.
The a ? b : c construct inside the first hashes is the ternary conditional operator - a compact way of doing if/else - supported in CF10 and Railo 3.3 onwards.
If a name doesn't have an explicit label, it replaces underscores with spaces, which is probably preferable if the report is for a non-technical audience.
If it's possible that you have code that adds (or removes) items in the form scope without modifying the FieldNames list, you can change the loop for this...
<cfloop item="CurField" collection=#Form# >
<cfif CurField EQ 'FieldNames'>
<cfcontinue />
</cfif>
...
Which looks at the actual keys in the Form scope - though the ordering of them is not guaranteed for this method.
How about you loop on the struct itself directly ?
<cfscript>
for(eachKey in FORM){
if(FORM[eachKey] neq ''){
writeOutput('<li>' &
FORM[eachKey] & ' = ' &
trim( FORM[eachKey] ) &
'</li>');
}
}
</cfscript>
You can have a space in the form variable name.
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>
I have the below code:
<cfset abcList = "*,B,b,A,C,a">
<cfset abcList=ListToArray(abcList,',')>
When I output 'abcList' then it is giving me a value but when I use the 'abcList' in <cfif> it's not working. Here is the code which is creating the problem:
<cfoutput>
#abcList[1]# <!---This is giving '*' as Correct o/p--->
<cfif #abcList[1]# eq '*'> <!---Here its going in else--->
list has * at first place
<cfelse>
* is not first
</cfif>
</cfoutput>
Any suggestions on what's wrong in my code?
You don't necessarily need to convert the list to an array. If you are starting from a list variable, you may use Coldfusion list functions to do the same thing without specifying the array conversion.
<cfset abcList = "*,B,b,A,C,a">
<cfif Compare(listGetAt(abcList, 1), '*') EQ 0>
Match
<cfelse>
No Match
</cfif>
Note that most of Coldfusion's string comparisons are not case sensitive. So if you need to test that 'B' is not the same as 'b', you will need to use the compare() function or else use one of the Regular Expression string functions. In this case, compare() returns 0 if string 1 equals string 2. If you do not need case sensitivity, then you may simplify further:
<cfset abcList = "*,B,b,A,C,a">
<cfif listGetAt(abcList, 1) EQ '*'>
Match
<cfelse>
No Match
</cfif>
It also works fine for me. Perhaps you have some extra spaces in the list values? That would skew the results:
<cfset abcList = "#chr(32)#*,B,b,A,C,a">
<cfset abcList=ListToArray(abcList,',')>
<cfoutput>
The value of abcList[1] = #abcList[1]# <br/>
<cfif abcList[1] eq '*'>
list has * at first place
<cfelse>
The else condition was hit because abcList[1] is "(space)*" and not just "*"
</cfif>
</cfoutput>
Try trimming the value first. Also, the # signs around the value are not needed.
<cfif trim(abcList[1]) eq '*'>
....
</cfif>
If that does not work, display the ascii values of both characters. Perhaps they are different than you are thinking.
<cfoutput>
ASCII abcList[1] = #asc(abcList[1])# <br/>
ASCII "*" = #asc("*")# <br/>
</cfoutput>
<cfset abcList = "*,B,b,A,C,a">
<cfset abc=ListToArray(abcList)>
<cfif #abc[1]# eq "*">OK<cfelse>FAIL</cfif>
<cfif abc[1] eq "*">OK<cfelse>FAIL</cfif>
Prints "OK OK" for me. Can you re-confirm it prints something else for you?