Dynamic rowspan in a Table Coldfusion - oracle

Just to give some background. We have users in different parts of the region. Our application sends out reports in emails which can be accessed via a URL. This way we keep a track on who accessed the report and various other attributes.
Now, as part of the statistics, I am trying to display the attributes in a HTML table.
I have the query which contains the details about the "Region Name", "UserID", "ReportName", "AccessCount", "ViewDate" etc.
The requirement is to span the "Region Name" across all its rows.
For ex. 10 different users from Melbourne region have access a report XYZ.
My table should have Melbourne with rowspan = "10" and each row having each users' details.
I don't want Melbourne to repeat 10 times in the table.
I've tried using the <cfoutput group="RegionName" tag along with the HTML table but the table is not well-formed.
How can I achieve this?

You should be able to achieve this and you were along the right direction by looking at the groupby attribute (actually the attribute is group=""). The cfml won't look very pretty though (I prefer cfscript and likely would do the following with a few functions). Something like the following should render a well-formed table with the RegionName cell spanning multiple rows in a well-formed manner, just adjust with classes / formatting etc. as you see fit!
<!---
Make sure that myQuery is ordered by
RegionName ASC before anything else to
ensure the group by works as intended
--->
<table>
<thead>
<tr>
<th>Region</th>
<th>User</th>
</tr>
</thead>
<tbody>
<cfoutput query="myQuery" group="RegionName">
<!--- set up an array to hold the users for this region --->
<cfset arrOfUsers = ArrayNew(1)>
<cfoutput>
<cfset ArrayAppend(arrOfUsers,'<td>'&myQuery.UserName&'</td>)>
</cfoutput>
<!--- render time, use the array just generated so we know how many users are in this group --->
<cfloop from="1" to="#ArrayLen(arrOfUsers)#" index="i">
<tr>
<cfif i EQ 1>
<td rowspan="#ArrayLen(arrOfUsers)#">#myQuery.RegionName#</td>
</cfif>
#arrOfUsers[i]#
</tr>
</cfloop>
</cfoutput>
</tbody>
</table>

Related

Coldfusion, Dropdown menu, Can a single option value contain multiple variables?

I am writing a CFM file to display a dropdown menu, in the dropdown options I want Var1 [Var2, Var3] to display for each line. I tried both concatenation and commas, tried a mix of brackets and quotes and cannot find the right combination. Using Oracle SQL developer. I am a student taking a database management class. I read through Adobe's site and cannot find an example like this. I also combed stack, but everything is PHP and javascript related. The result should have a dropdown, where each selection shows: cus_code with corresponding [cus_fname, cus_lname] for each line. Below is the query that pulls the data needed and the dropdown menu. The place I am having trouble is in the output, where each line from the dropdown should have 3 variables. Every attempt I make causes an error.
<!--Here is my query: grab customer code, last name, first name from customer table, join invoice table on customer code-->
<CFQUERY NAME="INVOICESEARCH" DATASOURCE="ORCL">
SELECT DISTINCT levine04.CUSTOMER6.CUS_CODE, CUS_LNAME, CUS_FNAME
FROM levine04.CUSTOMER6, levine04.INVOICE6
WHERE levine04.CUSTOMER6.CUS_CODE = levine04.INVOICE6.CUS_CODE;
</CFQUERY>
<!--Here is my dropdown:-->
<TR>
<TD ALIGN="right">INV_NUMBER</TD>
<TD>
<INPUT TYPE ="text" NAME="INV_NUMBER" SIZE="10" MAXLENGTH="10">
</TD>
</TR>
<TR>
<TD ALIGN="right">CUS_CODE, [CUS_FNAME, CUS_LNAME]</TD>
<TD>
<SELECT NAME="CUS_CODE" SIZE=1>
<OPTION SELECTED VALUE="ANY">ANY
<CFOUTPUT QUERY="INVOICESEARCH">
<OPTION VALUE="#INVOICESEARCH.CUS_CODE#" + "#INVOICESEARCH.CUS_LNAME#" +"#INVOICESEARCH.CUS_FNAME#"> #CUS_CODE# + #CUSLNAME# + #CUSFNAME#
</CFOUTPUT>
</SELECT>
</TD>
</TR>
Got it! But maybe this will help someone else..
<OPTION VALUE="#INVOICESEARCH.CUS_CODE#"> #CUS_CODE#[#CUS_LNAME#, #CUS_FNAME#]

passing 2 values from cfselect based on selection from dropdown?

This is only my second question on SO, and I'm brand new to web coding of all kinds (anything I've done I've picked up within the last 3 weeks so I don't really know what I'm doing) but here's some background and my issue:
Background info:
I'm updating some existing pages that previously had, no joke, 42 different dropdown menus to show data maps for different water bodies and sampling dates. So I'm condensing that down to a slightly more elegant (though still way dated) approach of all of that in 2 dropdown menus where users can choose whatever combo of tributaries and sampling dates they want to see data for.
I have 2 dynamic related dropdowns using a CFC and CFM (those are working great, thanks to help from SO). THE CFC has the functions, queries, arguments to get the data from the database. The CFM displays the first dropdown menu (a list of tributaries), and when a user selects from that, a second dropdown is populated with dates that the tributary/ies were sampled. The 'display' of this 2nd dropdown is tributary name appended to the beginning of the date so they displays as a 'tribdate', like "Back River: Apr 07, 2014". When a user selects what they want from the second dropdown (named 'link') and hits submit, the sent value(s) are path strings ('File_html') which, on the target page, result in maps of data being displayed for those tributaries on those dates. In the target page the 'form.link' is defined, loops, and shows all the data map images (ie. 'File_html') correctly.
My issue:
Above each image that is displayed I want to have the "tributary" name and the "sampling date" but I don't know how to pass this information. I am passing the 'File_html' but I would like to pass 'tribdate' (the display value) or pass 'tributary' or 'cruisedate' separately. Or even use the alt text from the image, but I don't know how to do that either.
What I've tried:
(1) I can't pull a usable tributary name out of the value that is passed (many are partial names), but I can pull a usable tributary date.
(2) If I pull the 'tributary' name from the 1st dropdown where tributary is selected and try to use that to title the maps it only works for one map (which makes sense bc only 1 tributary is selected). So if a user selects 2 dates from 'Back River' only one map can be displayed with the title of 'Back River' and there's an error for the second. If there's a way to replicate this tributary value to be reused when needed, that would be great.
(3) I tried making a 3rd dropdown which just shows the tributary name for the dates selected and then on the mapdisplay using the name of that dropdown menu for the title name, which works, but I can't really have people select those, I want them automatically passed.
Can I call tributary from the CFC? Can I send 'tribdate' to the mapdisplay page? Any help, hints, ideas would be great, thank you.
I saw this question which is essentially what I'm asking but I don't really understand where to put the answer that was given: Using CFQUERY and CFSELECT to pull multiple values based on selection
The CFC:
<cfcomponent displayname="GetStuff" hint="Getting data on cruises from database">
<!---Get list of Tributaries--->
<cffunction name="getData"
access="remote"
returntype="query"
hint="Get data for tributary dropdown">
<!---define variables--->
<CFSET VAR data="">
<!---Run the query for tributaries--->
<cfquery name="data" datasource="mydatasource">
SELECT DISTINCT Tributary
FROM df_cruises
ORDER BY Tributary
</cfquery>
<!---and return it--->
<cfreturn data>
</cffunction>
<!---Get Dates by Tributary--->
<cffunction name="getDates"
access="remote"
returntype="query"
hint="Get cruise dates by tributary for select dropdown">
<cfargument name="Tributary" type="any" required="no" multiple="yes">
<!---define variables--->
<cfset var data="">
<!---Run query to get Date Data and add Trib name to front, and get File_html to send to MapDisplay--->
<cfquery name="data" datasource="mydatasource">
SELECT File_html, Tributary, (Tributary + ':' + SPACE(2)) + CONVERT(varchar(12), CruiseDate, 107) AS tribdate
FROM df_cruises
WHERE Tributary IN (<cfqueryparam cfsqltype='cf_sql_varchar' list="yes" value='#ARGUMENTS.Tributary#'>)
ORDER BY tribdate
</cfquery>
<!---And return it--->
<cfreturn data>
</cffunction>
</cfcomponent>
CFM which has the dropdowns/form:
<cfform name="CruiseChoose" action="mapdisplayv5.cfm" method="post">
<td align="center">
<strong>Tributary/Water Body:</strong><br />
<cfselect name="Tributary"
size="7" class="dynamicdropdown"
multiple="yes"
value="Tributary"
display="Tributary"
bind="cfc:UsingBook.getData()"
bindonload="yes"/>
</td>
<td align="center"><br />
<strong>Sampling Dates:</strong><br />
<cfselect name="link"
size="7" class="dynamicdropdown"
multiple="yes"
value="File_html"
display="tribdate"
bind="cfc:UsingBook.getDates({Tributary})"
bindonload="false"
type="any"/>
</td>
The target CFM page which displays the data maps:
<!---mapdisplayv5.cfm--->
<tr>
<td>
<p><p><cfoutput>
<cfif IsDefined("form.link")>
<br>
<cfset cnt= 1>
<cfloop index="listing" list="#form.link#" delimiters=",">
<cfset Tributary=#listGetAt(form.link, cnt)#>
<div align="center">
<font size="4"><b>#Tributary#<cfset cnt=cnt> - <cfset tribdate=#listGetAt(form.link, cnt)#> #right(tribdate, 6)# </b></font>
<cfset wqmimage=#listGetAt(form.link, cnt)#>
<table width="85%" border="1" bordercolor="##000000">
<tr>
<td><cfinclude template="images/#Ltrim(wqmimage)#.html"></td>
</tr>
</table>
Click here for Enlarged Map (WARNING-Large File Size)<Br>
<cfif listlen(form.link)Less Than or Equal to #cnt#>
<cfbreak>
</cfif>
<cfset cnt=cnt+1>
<br><br><hr>
</cfloop>
<cfelse>
<b>
<p align="center"><br><br><br><br>No Selection Was Made.<br>Please Return to the Previous Page and Make Your
Selection</p></b><Br>
<br><br><br>
</cfif>
</p>
</cfoutput></p>
UPDATE:
On the CFM page that has the form I am now passing the PK "ID" to the mapdisplayv5.cfm, below is the new code for that. It now relates the correct title and shows the image that I want and will show multiple, but each multiple is a copy of whatever the first selection is from the second dropdown. So if you choose 2 different dates, it shows 2 copies of the first date you chose.
Snapshot of the change to the 2nd dropdown on the CFM with the form, note that I am now passing ID:
<td align="center"><br />
<strong>Sampling Dates:</strong><br />
<cfselect name="link"
size="7" class="dynamicdropdown"
multiple="yes"
value="ID"
display="tribdate"
bind="cfc:UsingBook.getDates({Tributary})"
bindonload="false"
type="any"/>
</td>
Change to the mapdisplay.cfm page:
<!---mapdisplayv5.cfm--->
<tr>
<td>
<p><cfoutput>
<cfif IsDefined("form.link")>
<cfquery name="retrieve" datasource="mydatasource">
SELECT File_html, Tributary, CruiseDate, (Tributary + ':' + SPACE(2)) + CONVERT(varchar(12), CruiseDate, 107) AS tribdate
FROM df_cruises
WHERE ID IN (<CFQUERYPARAM VALUE='#FORM.link#' list='yes' CFSQLTYPE='CF_SQL_INTEGER'>)
</cfquery>
<cfset cnt= 1>
<cfloop index="listing" list="#form.link#" delimiters=",">
<br>
<cfset wqmimage=#retrieve.File_html#>
<cfset tributary=#retrieve.Tributary#>
<cfset tribdate=#retrieve.tribdate#>
<div align="center">
<font size="4"><b>#tribdate#</b></font>
<cfinclude template="images/#Ltrim(wqmimage)#.html">
Click here for Enlarged Map (WARNING-Large File Size)<Br><br>
<cfif listlen(form.link)Less Than or Equal to #cnt#>
<cfbreak>
</cfif>
<cfset cnt=cnt+1>
</cfloop>
<cfelse>
<br>
<p align="center"><br><br><br><br>No Selection Was Made.<br>Please Return to the Previous Page and Make Your
Selection</p></b><Br>
<br><br><br>
</cfif>
</cfoutput>
UPDATE 2:The corrected, working version of the mapdisplayv5.cfm
(THANK YOU luke, Dan, and Leigh!)
<!---mapdisplayv5.cfm--->
<tr>
<td>
<p>
<cfif IsDefined("form.link")>
<cfquery name="retrieve" datasource="tideRO">
SELECT File_html, Tributary, CruiseDate, (Tributary + ':' + SPACE(2)) + CONVERT(varchar(12), CruiseDate, 107) AS tribdate
FROM df_cruises
WHERE ID IN (<CFQUERYPARAM VALUE='#FORM.link#' list='yes' CFSQLTYPE='CF_SQL_INTEGER'>)
</cfquery>
<br><cfoutput query="retrieve">
<cfset wqmimage=#retrieve.File_html#>
<cfset tributary=#retrieve.Tributary#>
<cfset tribdate=#retrieve.tribdate#>
<div align="center">
<font size="4"><b>#tribdate#</b></font>
<cfinclude template="images/#Ltrim(wqmimage)#.html">
Click here for Enlarged Map (WARNING-Large File Size)<Br><br></cfoutput>

HtmlAgilityPack algorithm question

I’m using HtmlAgilityPack to obtain some Html from a web site.
Here is the received Html:
<table class="table">
<tr>
<td>
<table class="innertable">...</table>
</td>
</tr>
<tr>
<td colspan="2"><strong>Contact</strong></td>
</tr>
<tr>
<td colspan="2">John Doe</td>
</tr>
<tr>
<td colspan="2">Jane Doe</td>
</tr>
<tr>
<td colspan="2"> </td>
</tr>
<tr>
<td><strong>Units</strong></td>
<td>32</td>
</tr>
<tr>
<td><strong>Year</strong></td>
<td>1998</td>
</tr>
</table>
The Context:
I’m using the following code to get the first :
var table = document.DocumentNode.SelectNodes("//table[#class='table']").FirstOrDefault();
I’m using the following code to get the inner table :
var innerTable = table.SelectNodes("//table[#class=innertable]").FirstOrDefault();
So far so good!
I need to get some information from the first table and some from the inner table.
Since I begin with the information from the first table I need to skip the first row (which holds the inner table) so I do the following:
var tableCells = table.SelectNodes("tr[position() > 1]/td");
Since I now have all the cells from the first table excluding the inner table, I start doing the following:
string contact1 = HttpUtility.HtmlDecode(tableCells[1].InnerHtml);
string contact2 = HttpUtility.HtmlDecode(tableCells[2].InnerHtml);
string units = HttpUtility.HtmlDecode(tableCells[5].InnerHtml);
string years = HttpUtility.HtmlDecode(tableCells[7].InnerHtml);
The problem:
I’m getting the values I want by hardcoding the index in tableCells[] not thinking the layout would move…unfortunately, it does move.
In some cases I do not have a “Jane Doe” row (as shown in the above Html), this means I may or may not have two contacts.
Because of this, I can’t hardcode the indexes since I might end up having the wrong data in the wrong variables.
So I need to change my approach...
Does anyone know how I could perfect my algorithm so that it can take into account the fact that I may have one or two contacts and perhaps not use hardcoded indexes?
Thanks in advance!
vlince
There is never one unique solution to this kind of problem. Here is an XPATH that seems to do some kind of it though:
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.Load(yourHtmlFile);
doc.Save(Console.Out);
foreach (HtmlNode node in doc.DocumentNode.SelectNodes("//tr[td/strong/text() = 'Contact']/following-sibling::tr/td/text()[. != ' ']"))
{
Console.WriteLine(node.OuterHtml);
}
will display this:
John Doe
Jane Doe
32
1998

Using jQuery Validate to ensure there is at least one row in my table

I am using a table in an entry program to allow the user to add one or more rows of information (much like this article).
I need to ensure that there is at least one row in this table. Google is not really turning much up for me on people doing this. Can anyone give me direction on this? Can I do a count based on a class name?
Here is the layout of my table:
<table id="editorRows">
...
<tbody class="editorRow">
<tr class="row1">
</tr>
<tr class="row2" style="display: none;">
</tr>
<tr class="row3" style="display:none;">
</tr>
</tbody>
</table>
A "row" in this case is the tag. Row 2 and 3 get dynamically showen based on options in row 1.
you can use $("#editorRows tr").length > 0

How to reorder struct columns?

I'm trying to display my results from a CFQuery in a specific order. The order is to be maintained in the database so that it can be manipulated, and there are an unknown number of columns per table. The final row in the table is "ColumnOrder": each column has a number to specify it's sort order, 0 means "don't display". I'm trying to sort by looping say, "y" from 1 to maxCols:
0) do y = 1 to maxCols
1) in the sortColumn result set, use y to lookup the corresponding KEY
2) in the products result set, find the value from the corresponding KEY
3) insert said value into tempStruct[y]
4) loop.
I'm running into a wall trying to use structFindKey(). Here's my code:
<CFQUERY name="qParts" datasource="Pascal">
SELECT * FROM Turbos WHERE PartNumber LIKE <cfqueryparam cfsqltype="cf_sql_char" maxlength="30" value="%#mfr#%"> ORDER BY #sort# ASC
</CFQUERY>
<cfquery name="qPartsOrder" datasource="Pascal">
SELECT * FROM Turbos WHERE PartNumber = 'ColumnOrder'
</cfquery>
<cfset tempStruct=structnew()>
<cfloop index="columnOrder2" from="1" to="#ListLen(qPartsOrder.ColumnList, ',')#">
<cfdump var="#StructFindKey(qPartsOrder, columnOrder2)#">
<cfset tempStruct[columnOrder2] = StructFindKey(#qPartsOrder#, "#columnOrder2#")>
<cfset currentCol = "#ListGetAt(qParts.columnList, columnOrder2, ',')#">
<cfoutput>#qParts[currentCol][qParts.currentrow]# <br/></cfoutput>
</cfloop>
<cfdump var="#tempstruct#">
The line
<cfdump var="#StructFindKey(qPartsOrder, columnOrder2)#">
is throwing a BLANK!! error message, so I can't debug it and I'm stuck.
Any and all help would be appreciated (and YES I have to use SELECT *, this is a generic product display page for displaying ALL information in the database except a few which are denoted by a zero in the order column, remember?).
I'm not 100% sure that I understand the problem you are trying to solve. The is exacerbated by a very unconventional way of setting up a database.
To begin with, if you are not lucky you may run into a documented error where using a cfqueryparam tag throws an error of Value cannot be converted to requested type although I don't know if this still happens with current versions of ColdFusion (8+).
In any case, you can always select all of the columns of the table manually even if you don't know how many of them will ultimately be used:
SELECT partNumber, secondColumn, thirdColumn, ... , nthColumn
FROM Turbos
This is generally preferable to just using SELECT * although it presents some problems if you are in the habit of frequently adding/removing columns to tables.
Unless you need to use a Struct for good reason, you should use an Array instead. Structs don't store ordering information while Arrays do. Here is one way to sort through the records in qParts:
<cfset RecordsArray=ArrayNew(2)>
<cfset ColumnIndex=StructNew()>
<cfloop list="#qPartsOrder.ColumnList#" index="order_column">
<cfset ColumnIndex[order_column]=val(qPartsOrder[order_column][1])>
</cfloop>
<cfloop query="qParts">
<cfloop list="#qPartsOrder.ColumnList#" index="order_column">
<cfif val(ColumnIndex[order_column])>
<cfset RecordsArray[ColumnIndex[order_column]][qParts.CurrentRow]=qParts[order_column][qParts.CurrentRow]>
</cfif>
</cfloop>
</cfloop>
The result of this code will be a 2D array, with the first number referring to the column index and the second index pointing to the record row.
All in all, I think that unless you have zero control over how the database is structured, there is a better way to implement this, starting with how you've set up your database. It would really help to see some fake sample data as well as having a clearer idea of what you are trying to accomplish -- what will you do with these ordered fields once you have them, for example?
Dun you try to use StructSort ?

Resources