Display single digits with leading zero - coldfusion

I am trying to make a minutes dropdown. How do I make it come out as 01, 02, 03, 04, 05, 06, 07 08, 09, 10, 11, 12, etc.? Right now the first 9 numbers only come out as 1, 2, 3, 4, 5, 6, 7, 8, 9.
<select id="minutes">
<cfloop from="1" to="60" index="m">
<option>#m#</option>
</cfloop>
</select>
Well, I understand why it's doing what it's doing and was expecting it anyway. Haha. Just wondered if there was a way of getting the 0s to come up without having to manually create 01-09 options.

You can use numberFormat.
<select id="minutes">
<cfoutput>
<cfloop from="1" to="60" index="m">
<option>#numberFormat(m,'00')#</option>
</cfloop>
</cfoutput>
</select>
See also this runnable example at trycf.com.

I can think of two options off the top of my head:
Option 1 - cfloop over timespan
Create a start and end time, and use cfloop with a step value of one minute (source: adobe docs )
<cfset startTime = CreateTime(0,0,0)>
<cfset endTime = CreateTime(0,59,59)>
<select id="minutes">
<cfoutput>
<cfloop from="#startTime#" to="#endtime#" index="m" step="#CreateTimeSpan(0,0,1,0)#">
<option>#TimeFormat(m, 'mm')#</option>
</cfloop>
</cfoutput>
</select>
Option 2 - use RIGHT()
Just prepend 0 to all values, and take the right two characters:
<select id="minutes">
<cfoutput>
<cfloop from="0" to="59" index="m">
<option>#Right(0 & m, 2)#</option>
</cfloop>
</cfoutput>
</select>

Related

Split the session variable into an array using recreating individual session variables

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>

CFLoop and ListValueCount

I am tallying student evaluation of instructors. I want my results to appear as:
Instructor1 - 145
Instructor2 - 23
Instructor3 - 394
The #CountInstructor# is not changing. It is only the first count is correct.
Using Coldfusion 8.
Thanks for your help.
<CFQUERY NAME="GetAll" datasource="eval" dbtype="ODBC">
SELECT ID, Instructor, Q1, Q2, Q3, Q4, Q5, Q6
FROM data
</CFQUERY>
<CFQUERY NAME="GetInstructor" datasource="eval" dbtype="ODBC">
SELECT DISTINCT Instructor
FROM data
ORDER BY Instructor
</CFQUERY>
<cfset myInstructor = ValueList(GetInstructor.Instructor)>
<cfset myCountInstructor = ValueList(GetAll.Instructor)>
<cfset CountInstructor = ListValueCount(myCountInstructor, myInstructor)>
<cfoutput query="GetAll">
<cfset CountInstructor = ListValueCount(myCountInstructor, GetInstructor.Instructor)>
#GetInstructor.Instructor# - #CountInstructor# <br />
</cfoutput>
Your use of ListValueCount(), within your query output loop, isn't helping you any. What is it you're trying to do exactly? If all you're looking to do is output a count as you go...
<cfoutput query="GetInstructor">
#GetInstructor.Instructor# - #GetInstructor.CurrentRow#
</cfoutput>
Otherwise, I'm just not sure what you want to do (and you need to scope all of the variables, including the query names).
<cfoutput query="GetInstructor">
<cfset CountInstructor = ListValueCount(myCountInstructor, GetInstructor.Instructor)>
#GetInstructor.Instructor# - #CountInstructor# <br />
</cfoutput>

ColdFusion: Can you pull out a unique record from a query using recordCount?

It's a bit of tricky question, however, my page for most rated bands displays the band logos in order of how high they have been rated. My only problem is i want to count through the records by using a cfloop from 1 to 10 and because it is split in to two columns, have one counting 1 through to 9 and the other 2 through to 10, each of them with steps of two.
Can anybody help me with this? If i've confused just mention it and ill try to clarify exactly what i mean.
<DIV class="community_middle">
<cfoutput query="top10MostRated">
<cfloop from="2" to="10" index="i" step="2">
<DIV class="communityContent">
#chr(i)#
<IMG src="logo/#top10MostRated.Logo#" alt="#top10MostRated.Name#" width="100%" height="100%"></IMG>
</DIV>
<BR/>
</cfloop>
</cfoutput>
</DIV>
If you're looking to do odd/even lists separately, then you can use the currentrow property of the query combined with the modulo operator (%) to work out if the row is odd or even:
<cfloop query="topBands>
<cfif topBands.currentRow % 2 = 1>
<!--- do your odd number output here --->
</cfif>
</cfloop>
<cfloop query="topBands>
<cfif topBands.currentRow % 2 = 0>
<!--- do your even number output here --->
</cfif>
</cfloop>
I think these answers address your side-by-side part of your question but does not explain the "same image" issue. Their code is written correctly but does not explain the reason.
Your code:
<IMG src="logo/#top10MostRated.Logo#"
alt="#top10MostRated.Name#"
width="100%" height="100%"></IMG>
... would be fine if you were only inside a <cfloop query = "top10MostRated"> or <cfoutput query = "top10MostRated"> block. The reason is because inside these types of blocks CF is smart enough to know you want the data for the current row. It would be the same as:
<IMG src="logo/#top10MostRated.Logo[top10MostRated.currentRow]#"
alt="#top10MostRated.Name[top10MostRated.currentRow]#"
width="100%" height="100%" />
Because you're nesting the to/from cfloop inside a <cfoutput query = ""> block, you are getting unexpected results. Your existing code is always asking for the record provided by your outer loop. Hence you see the same image 5 times. (using any of the fine examples provided will help you get out of this) but, you can remove the query from your cfoutput and simply ask CF to show you the value for the correct row in your loop using your index (you set your index to "i") so the below would show you the image that corresponds to your loop.
<IMG src="logo/#top10MostRated.Logo[i]#"
alt="#top10MostRated.Name[i]#"
width="100%" height="100%" />
It sounds like what you'd like to get is a collection of even-numbered records and a collection of odd-numbered records. In Coldfusion 10 or Railo 4, you can use groupBy() from Underscore.cfc to split up your query result into manageable sub-sets, like so:
_ = new Underscore();// instantiate the library
groupedBands = _.groupBy(topBands, function (val, index) {
return index % 2 ? "odd" : "even";
});
This returns a struct with two elements odd and even, each containing an array of records which are odd or even. Example result:
{
odd: [{name: "Band one"}, {name: "Band three"}],
even: [{name: "Band two"}, {name: "Band four"}]
}
Splitting your results into logical sub-sets makes the code more readable:
<cfoutput>
<cfloop from="1" to="5" index="i">
<div class="left">#groupedBands.odd[i].name#</div>
<div class="right">#groupedBands.even[i].name#</div>
</cfloop>
</cfoutput>
You'll also be able to use those sub-sets in other places on your page if you need to.
Note: I wrote Underscore.cfc
Ben Nadel has a post exactly for this. Link here
A breakdown for this is
<cfloop query="top10MostRated">
<cfif top10MostRated.CurrentRow MOD 2>
<!--- Add to the "odd list" --->
<cfelse>
<!--- Add the record to the "even list" --->
</cfif>
</cfloop>
Then you'll have 2 lists oddList and evenList. Then it's just a matter of displaying them.
I'd do it a different way. The objective is to have records 1 and 2 side by side and I don't see that in #barnyr's answer.
<cfoutput>
<cfloop from="2" to="topbands.recordcount + 1" index = "i" step="2">
#topbands.fieldname[i-1]#
<cfif i lte topbands.recordcount>
#topbands.fieldname[i]# <br />
</cfif>
</cfloop>
</cfoutput>

Transpose query in ColdFusion

I have a simple cfquery which outputs 3 columns with their respective data. The columns are name, address and age.
I want to transpose this set of data so that the names become the columns and the address and age are displayed under each column.
I know that we can use QueryAddColumn or something like this for this issue. Can someone help me out with this problem?
EDIT:
Based on the comment below this is the intended output:
Oct 2011 Nov 2011 Dec 2011 Jan 2012 Feb 2012
NumberofPeople NumberofPeople NumberofPeople NumberofPeople NumberofPeople
EmploymentRate EmploymentRate EmploymentRate EmploymentRate EmploymentRate
I have included a sample data row at the top where you would put your cfquery statement.
<cfset firstQuery = queryNew("date,NumberofPeople,EmploymentRate")>
<cfset aRow = queryAddRow(firstQuery)>
<cfset querySetCell(firstQuery,"date","OCT_2011",aRow)>
<cfset querySetCell(firstQuery,"NumberofPeople","28",aRow)>
<cfset querySetCell(firstQuery,"EmploymentRate","50%",aRow)>
<cfset aRow = queryAddRow(firstQuery)>
<cfset querySetCell(firstQuery,"date","NOV_2011",aRow)>
<cfset querySetCell(firstQuery,"NumberofPeople","28",aRow)>
<cfset querySetCell(firstQuery,"EmploymentRate","56%",aRow)>
<cfset aRow = queryAddRow(firstQuery)>
<cfset querySetCell(firstQuery,"date","DEC_2011",aRow)>
<cfset querySetCell(firstQuery,"NumberofPeople","29",aRow)>
<cfset querySetCell(firstQuery,"EmploymentRate","55%",aRow)>
<cfset aRow = queryAddRow(firstQuery)>
<cfset querySetCell(firstQuery,"date","JAN_2012",aRow)>
<cfset querySetCell(firstQuery,"NumberofPeople","30",aRow)>
<cfset querySetCell(firstQuery,"EmploymentRate","52%",aRow)>
<!--- Will Create new query with names as column headers--->
<cfset newQuery = queryNew(valueList(firstQuery.date,','))>
<!--- Will Create new query with names as column headers--->
<cfset people = queryAddRow(newQuery)>
<cfset rate = queryAddRow(newQuery)>
<cfloop query='firstQuery'>
<!---Syntax for this function is: QuerySetCell(query, column_name, value [, row_number ]) --->
<cfset querySetCell(newQuery,firstQuery.date,firstQuery.NumberofPeople,people)>
<cfset querySetCell(newQuery,firstQuery.date,firstQuery.EmploymentRate,rate)>
</cfloop>
<cfdump var="#newQuery#">
<cfdump var="#ArrayToList(newQuery.getColumnNames())#">
This is How I would Do it, But I can't think of why I would do it. I'd be interested to hear your use case. Anyway, I hope this helps.
(P.S This is tested in CF9, so you should be able to copy and paste it to test for yourself.)
EDIT -(Again):
Forgot to mention, this can only work if the names your retrieveing from the DB are valid column names, so no spaces (In this example spaces in dates have been replaced by underscores)!
>>> New code snippet for the updated data structure, the function valueList(firstQuery.date,',') doesn't re-order your columns. The columns are re-ordered on output when dumping. I have used the function ArrayToList(newQuery.getColumnNames()) to show that internally CF maintains the column order and you need only ask it nicely. You should be able to use all this information to nicely output your data how you need it.
Maybe I'm missing something but it seems like a simple SQL query with the ORDER BY clause would work. Something like this:
<cfquery name="myquery" datasource="yourdatasourcename">
select name, address, age
from tablename
order by name
</cfquery>
Then in your ColdFusion output page, you can use the tag with the group attribute. Something like this:
<cfoutput query="myquery">
<p>name = #name#
<cfoutput group="name">
age = #age#
address = #address#<br />
</cfoutput>
</p>
</cfoutput>
Obviously, you can format the output however you wish.
EDIT --
If you are wanting to display like:
Mary Joe Sam Suzie
28 36 25 42
123 Maple 16 Oak 3723 Street 832 Busy St.
Perhaps something like (I have not tested this, just brainstorming):
<cfoutput query="myquery" group="name">
<div style="float:left;">name = #name#
<cfoutput>
<p>
age = #age#<br />
address = #address#
</p>
</cfoutput>
</div>
</cfoutput>
I think you are describing a pivot query in SQL.

Limiting number of pages on a paging list

I am working on revamping a sites' paging system, and I have run into something simple I can't seem to solve. I am trying to show pages (1 2 3 4 5) at a time, and when the user gets to page 5, the list changes to something like (4 5 6 7 8). How could I do this using a cfloop? Here is a sample of my code:
<cfloop from="1" to="#totalPages#" index="i">
<cfoutput><a class="paging" href="?start=#(i*25)-24#">#i#</a></cfoutput>
</cfloop>
At the moment it shows pages 1 - 54 all at once. Any tips?
Heres my code
<cfset curPage = Int(start / 25) + 1>
<cfloop from="1" to="#totalPages#" index="i">
<cfif i is curPage>
<div class="page current">#i#</div>
<cfelse>
<cfif totalPages lte 5 or i is 1 or i is totalPages or (i gt curPage - 3 and i lt curPage + 3) or ((curPage is 1 or curPage is 2) and i lt 6) >
<div class="page">#i#</div>
<cfelse>
<cfif i is 2 or i is totalPages - 1>
<div class="more">...</div>
</cfif>
</cfif>
</cfif>
</cfloop>
What this code does is it shows the first 5 pages, then an ellipsis, then the last page. As you page through it, it will always show the link to the first and last page, plus 2 page before and after the current page.
Screenshots: Page 1 and page 10
You should be able to easily modify this to work exactly how you want it. (I happen to not like when all of the links change at once the way you described)
There is a great open source pagination library that will solve your problem. I can't say enough good things about it because I wrote it. Shameless, I know. Anyways:
http://www.dopefly.com/projects/pagination/
Check out the docs, they are very complete and helpful. In your code, printing the page numbers are as simple as calling #pagination.getRenderedHTML()#. It is pretty customizable so that you can change the numbers that are printed and you can style the output however you like.
How about:
<cfloop from="#url.startpage#" to="#url.startpage+4#" index="i">
<cfif i LE totalpages>
<cfoutput><a class="paging" href="?start=#(i*25)-24#">#i#</a></cfoutput>
</cfif>
</cfloop>
Of course you would need to add "startpage" to your url and manipulate it appropriately. So your first link would be startpage=1 but your last would be startpage=4 (if I understand your question correctly).