Looping over data submittted via jquery ajax routine with Coldfusion - coldfusion

If FF firebug window, I see this is being passed to my coldfusion action page:
RowOrder[]=&RowOrder[]=row_5&RowOrder[]=row_2&RowOrder[]=row_1&RowOrder[]=row_3&RowOrder[]=row_4&RowOrder[]=row_6&RowOrder[]=row_7&RowOrder[]=row_8&RowOrder[]=row_11
Now I need to loop over this to get the updated sort order but due to the [], I'm having issues. How can I loop over this so that I can update my table??? I expected this to be the easy part but I'm obviously missing something.
+ I'm using the jquery plugin (http://www.isocra.com/2008/02/table-drag-and-drop-jquery-plugin/). +
Here is the code I'm using to loop over the submitted data:
<cfif StructKeyExists(form, "RowOrder")>
<!---<cfset variables.Order = ReReplaceNoCase(form.RowOrder, "(&){0,1}row_\[\]=", ",", "all") />--->
<cfset variables.Order = ReplaceNoCase(form["RowOrder[]"],"row_","","all")>
<cfloop from="1" to="#ListLen(variables.Order)#" index="index">
<cfquery name="qryOrder" datasource="#dsn#">
update SystemTypes
set Order = <cfqueryparam value="#index#" cfsqltype="cf_sql_integer" />
where WETypeNum = <cfqueryparam value="#ListGetAt(variables.Order, index)#" cfsqltype="cf_sql_integer" />
</cfquery>
</cfloop>
</cfif>
+ The ajax code I'm using is as follows:
$("#RowOrder").tableDnD({
onDrop: function(table, row) {
var RowOrderData = $.tableDnD.serialize();
$.ajax({
type: 'POST',
url: '../../ajax/UpdateListingOrder.cfm',
cache: false,
data: RowOrderData
});
}
});
+
The + indicates information that was added after posting question

How is the problem manifesting itself? Are you getting an error, the query is not executing, .. ?
Dump the FORM scope to verify the name of field being passed? It looks like FORM['RowOrder[]'] rather than form.RowOrder. In which case you would need to use:
<cfif StructKeyExists(form, "RowOrder[]")>
<cfset variables.Order = ReReplaceNoCase(form["RowOrder[]"], "(&){0,1}row_\[\]=", ",", "all") />
... rest of code ...
<cfelse>
oops, that variable name does not exist
</cfif>

Could you not match the number rather than replace?
I've done the regex match within the loop - You can then focus on just one part of the string at a time.
An an illustration of the approch:
<cfif structKeyExists(form, "rowOrder")>
<cfset data = listToArray(form.rowOrder, "&")/>
<cfif not arrayIsEmpty(data)>
<cfloop form="1" to="#arrayLen(data)#" index="index">
<cfset match = reFind("[1-9][0-9]+", data[index], 1, true)/>
<cfif arraySum(match)>
<cfset weTypeNumber = val(mid(data[index], match["pos"], match["len"]))/>
<cfquery name="qryOrder" datasource="#dsn#">
UPDATE
system_types
SET
order = <cfqueryparam cfsqltype="cf_sql_integer" value="#index#"/>
WHERE
we_type_num = <cfqueryparam cfsqltype="cf_sql_integer" value="#weTypeNumber#"/>
</cfquery>
</cfif>
</cfloop>
</cfif>
</cfif>

Related

Loop over the cfquery tag values

I have the following query where I loop over a list of values but I am getting an error at the last comma:
<cfquery datasource="#application.dsn#">
INSERT INTO #session.tablename# ( #lFields# )
VALUES (
<cfloop list="#lFields#" index="kk">
<cfqueryparam value="#TRIM(sVideoGame['#kk#'])#" cfsqltype="cf_sql_varchar" null="#NOT LEN(TRIM(sVideoGame['#kk#']))#" />,
</cfloop>
)
</cfquery>
Problem occurs with the last comma. I tried setting up a counter before the cfloop, setting it 0 and incrementing to 1 inside the cfloop. However, I am not sure how to remove the last comma based upon some condition check.
In order to keep track of the position, you will need a from/to loop instead of a list loop. Then add a comma after you pass the first query parameter.
For ColdFusion 2016+ it can be done using the "item" and "index" attributes:
...
<cfloop list="#yourListVariable#" item="keyName" index="position">
<!--- if we've passed the first parameter, add a comma --->
<cfif position gt 1>,</cfif>
<cfqueryparam value="#TRIM(sVideoGame[ keyName ])#"
cfsqltype="cf_sql_varchar"
null="#NOT LEN(sVideoGame[keyName])#" />
</cfloop>
...
CF11 and earlier require a little more work. To simplify the code, I would recommend converting the list to an array:
<cfset keyArray = listToArray(yourListVariable)>
...
<cfloop from="1" to="#arrayLen(keyArray)#" index="position">
<!--- if we've passed the first parameter, add a comma --->
<cfif position gt 1>,</cfif>
<cfqueryparam value="#TRIM(sVideoGame[ keyArray[position] ])#"
cfsqltype="cf_sql_varchar"
null="#NOT LEN(sVideoGame[ keyArray[position] ])#" />
</cfloop>
...
Side note, I noticed the query uses dynamic table and column names. Be sure those values are NOT user supplied, or the query is vulnerable to sql injection.
If your only question is how to deal with the last comma, then you can do it with
<cfset listCount = 1>
<cfloop list="#lFields#" index="kk">
<cfqueryparam value="#TRIM(sVideoGame['#kk#'])#"
cfsqltype="cf_sql_varchar" null="#NOT LEN(TRIM(sVideoGame['#kk#']))#" />
<cfif listLen(lFields) is not listCount>,</cfif>
<cfset listCount = listCount+1>
</cfloop>

identifying the coldfusion value comng to run against query

I am passing dynamically named parameters in the url. (The number of sSearch parameters can go beyond 5 to 7 or 8 etc)
sSearch_0
sSearch_1
sSearch_2
sSearch_3
sSearch_4
sSearch_5
I want to run a loop to do a search within a query. I am trying like this:
<cfloop from="0" to="5" index="k">
<cfset counter = k>
<cfif IsDefined('url.sSearch_' & counter)>
<cfset "check_" & k = 'url.sSearch_' & counter>
</cfif>
</cfloop>
I am trying to write in a query like this:
<cfquery datasource="#coldfusionDatasource#" name="qFiltered">
SELECT *
FROM mytable
<cfif len(trim(url.sSearch))>
WHERE
<cfloop list="#listColumns#" index="thisColumn">
<cfif thisColumn neq listFirst(listColumns)> OR </cfif>
#thisColumn# LIKE <cfqueryparam cfsqltype="CF_SQL_VARCHAR"
value="%#trim(url.sSearch)#%" />
</cfloop>
</cfquery>
But it is not working. The error says check_ is undefined.
For dynamic variable naming using quotes, try:
<cfset "check_#k#" = 'url.sSearch_' & counter>
See this article

Need to insert the Upload count in the database and in table

I am getting the following details in my form. I need to loop through the fields which have "attachment" in the name and add the count to the table, and also the values in the new table.
ATTACHMENT C:\ColdFusion10\cfusion\runtime\work\Catalina\localhost\tmp\neotmp3230094756217875313.tmp
ATTACHMENT2 C:\ColdFusion10\cfusion\runtime\work\Catalina\localhost\tmp\neotmp4341408903737742616.tmp
ATTACHMENT3 C:\ColdFusion10\cfusion\runtime\work\Catalina\localhost\tmp\neotmp2809169853442728277.tmp
I am trying to do a loop over the form fields, but I am lost in between, and am unsure where to proceed.
<CFLOOP collection="#structform#" item="whichField">
<cfif FindNoCase('attachment',whichField)>
<cfset total = len(whichField)>
<cfoutput>#total#</cfoutput><br><br>
</cfif>
<CFOUTPUT>#whichField# = #structform[whichField]#</CFOUTPUT><br>
</CFLOOP>
I'm still not certain I've understood what's going on, so this might need tweaking/changing to make it work as needed, but this is without doubt a better approach:
<cfset Total = 0 />
<cfloop collection=#StructForm# item="FieldName" >
<cfif findNoCase('attachment',FieldName) AND len(StructForm[FieldName]) >
<cfset ++Total />
</cfif>
</cfloop>
<CFLOOP collection="#structform#" item="whichField">
<cfif FindNoCase('attachment',whichField)>
<cfset lstvalue = ListAppend(lstvalue,whichField)>
</cfif>
</CFLOOP>
<cfset total = ListLen(lstvalue)>
<cfif (len(total) AND total EQ 1) AND (Evaluate(lstvalue) EQ '')>
<cfset total = 0>
</cfif>

how to determine the rollback cause in a cftransaction

I have set of inserts that are wrapped in a <cftransaction> block, and I am getting a error and the insert is being rolled back.
Here is the code in question stubbed for space:
<cffunction name="InsertTCUV" access="public">
<cfargument name="vehicle required="true" type="xml" />
//Parsing the xml document here
<cftransaction>
<cfquery name="TCUVinsert datasource="mydb">
INSERT INTO tcuv
VALUES(...)
<cfquery>
<cfquery name="qLatestTCUVID" datasource="mydb">
SELECT TOP 1 tcuv_id FROM dbo.tcuv ORDER BY tcuv_id DESC
</cfquery>
<cfset curTCUVID = qLatestTCUVID.tcuv_ID>
<cfset optionsResult = insertOptions(curTCUVID,vehicle>
<cfset imagesResult = insertImages(curTCUVID,vehicle)>
<cfset standardFeaturesResult = insertStandardFeatures(curTCUVID,vehicle
</cftransaction>
</cffunction>
<cffunction name="insertOptions" access="private">
<cfargument name="TCUVID required="true type="numeric" />
<cfargument name="vehicleInfo" required="true" type="xml" />
<cfset var result = "good">
<cftry>
<cfset optionNode = xmlSearch(arguments.vehicleInfo[1], "p:RemarketingOption">
<cfloop index="i" from="1" to="#arrayLen(optionNode)#">
<cfset optionNodeNotes = XmlSearch(optionNode[#i#], "p:OptionNotes")>
<cfset optionNotes = "">
<cfloop index="j" from="1" to="#ArrayLen(optionNotesNodes)#">
<cfoutput>
<cfset optionNotes = optionNotes & " " & #optionNotesNodes[j].xmlText#>
</cfoutput>
</cfloop>
<cfquery name="insertOptions" datasource="mydb">
INSERT INTO dbo.tcuv_options
VALUES (
<cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.TCUVID#">,
<cfqueryparam cfsqltype="cf_sql_varchar" value='#xmlSearch(optionNode[i], "p:OptionID")[1].xmlText#'>,
<cfqueryparam cfsqltype="cf_sql_varchar" value='#xmlSearch(optionNode[i], "p:OptionTypeCode")[1].xmlText#'>,
<cfqueryparam cfsqltype="cf_sql_varchar" value='#xmlSearch(optionNode[i], "p:OptionShortDescription")[1].xmlText#'>,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#optionNotes#">
)
</cfquery>
</cfloop>
<cfcatch type="database">
//dumping cfcatch.* information
<cfset result = "error"
</cfcatch>
</cftry>
<cfreturn result>
</cffunction>
This whole thing is in a loop on the calling page, and everything works fine the first time through the loop. One the second pass, the TCUVInsert works, but I get to the insertOptions function, a coldfusion error is thrown saying that, variable insertOptions is undefined, and when I get the database, the second row isn't there, which tells me there was an error and the insert rolled back. So, there is an error with the insert of the options, and coldfusion isn't giving me the right error to diagnose it. So either I have to look in the database logs, which apparently are not setup, or try to extract the error from the cftransaction block, which I'm not sure how to do.
coldfusion 9, sql server 2008 r2
Any thoughts?
<cffunction name="insertOptions" access="private">
You are overwriting the function by using the same name for a query variable:
<cfquery name="insertOptions" datasource="imports">
Interestingly it is all because the query name was not var scoped. Functions are stored in the variables scope of the component. So by failing to localize the query name, you end up overwriting the function stored in variables.insertOptions when you run the query. Because insert statements do not return a resultset, that variable ends up being undefined. Hence the error. In this case the solution is to either scope the query name, or better yet remove it entirely (since it is not populated anyway).
Just one more reason to always var/local scope function variables - yes, query names too!

Why isn't my mysql query seeing this one combination of two variables but sees the rest?

I wrote a script that takes date entries and for some reason whenever I specify just a starting date with a blank end date the query never picks it up. Here's what I wrote.
<cfquery name="stec_mysql_loan_tracking_qry" result="meta_tracking" datasource="STLinux1MySQL">
Select
tslo.created,
tslo.created_by,
tslo.last_modified,
tslo.last_modified_by,
tslo.active,
tslo.is_manager,
tslo.pick_userid,
tslo.customer_code,
tslo.name,
tst.user_ip as ip,
tsl.loan_identifier,
tst.command,
tsl.tax_search_loan_id as id
From
tax_search_loan_officers tslo Left Join
tax_search_loans tsl On tsl.tax_search_loan_officer_id =
tslo.tax_search_loan_officer_id Left Join
tax_search_track tst On tst.pick_userid = tslo.pick_userid
Where
tslo.customer_code In (<cfqueryparam value="#tw_custcodes#" cfsqltype="cf_sql_varchar" list="yes">)
<cfif IsDefined('url.active')>
<cfif url.active neq "">
AND
tslo.active = <cfqueryparam value="#Trim(url.active)#" cfsqltype="cf_sql_varchar" list="yes">
</cfif>
</cfif>
<cfif IsDefined('url.is_managed')>
<cfif url.is_managed neq "">
AND
tslo.is_manager = <cfqueryparam value="#Trim(url.is_managed)#" cfsqltype="cf_sql_varchar" list="yes">
</cfif>
</cfif>
<cfif IsDefined('url.start_end')>
<cfif url.start_date neq "" and url.end_date eq "">
AND
<cfqueryparam value="#Trim(url.start_date)#" cfsqltype="cf_sql_date"> <= DATE_FORMAT(tslo.last_modified, '%Y-%m-%d')
AND
DATE_FORMAT(tslo.last_modified, '%Y-%m-%d') <= DATE_FORMAT(NOW(), '%Y-%m-%d')
</cfif>
</cfif>
<cfif IsDefined('url.start_date')>
<cfif url.end_date neq "" and url.start_date eq "">
AND
'2012-01-01' <= DATE_FORMAT(tslo.last_modified, '%Y-%m-%d')
AND
DATE_FORMAT(tslo.last_modified, '%Y-%m-%d') <= <cfqueryparam value="#Trim(url.end_date)#" cfsqltype="cf_sql_date">
</cfif>
</cfif>
<cfif isDefined('url.start_date')>
<cfif (url.start_date neq "") and (url.end_date neq "")>
AND
<cfqueryparam value="#Trim(url.start_date)#" cfsqltype="cf_sql_date"> <= DATE_FORMAT(tslo.last_modified, '%Y-%m-%d')
AND
DATE_FORMAT(tslo.last_modified, '%Y-%m-%d') <= <cfqueryparam value="#Trim(url.end_date)#" cfsqltype="cf_sql_date">
</cfif>
</cfif>
</cfquery>
And here is what it sees if url.end_date = "" but url.start_date = a value:
Select
tslo.created,
tslo.created_by,
tslo.last_modified,
tslo.last_modified_by,
tslo.active,
tslo.is_manager,
tslo.pick_userid,
tslo.customer_code,
tslo.name,
tst.user_ip as ip,
tsl.loan_identifier,
tst.command,
tsl.tax_search_loan_id as id
From
tax_search_loan_officers tslo Left Join
tax_search_loans tsl On tsl.tax_search_loan_officer_id =
tslo.tax_search_loan_officer_id Left Join
tax_search_track tst On tst.pick_userid = tslo.pick_userid
Where
tslo.customer_code In (?)
However, every other combination is fine. I've tried rewriting the cfif blocks but this structure is the only one that gets 2/3 while the rest fail.
(From the comments ..)
<cfif IsDefined('url.start_end')>
It looks like you have three date variables: url.start_date, url.end_date and url.start_end. What is url.start_end - is it a typo?
As an aside, you might want to set defaults values for the variables so you could eliminate some of the cfif conditions. Then work on simplifying the rest of the logic, because it seems more complex than is necessary ... Dan's response contains some good suggestions. I strongly suspect you could simplify the code and make the query more efficient to boot by getting rid of the DATE_FORMAT(ColumnName, '%Y-%m-%d') statements, because they will prevent the database from properly utilizing indexes on the referenced column.
Update:
After taking a closer look, I think this is what the code is trying to accomplish:
If both dates are present, filter on the given values
If only one of the dates is present, apply a default for the missing date. Then filter on both values.
If neither date is present, skip the filtering.
Something along these lines should mimic the behavior of current code. Note, it uses this type of comparison as a more index-friendly way of handling "time" issues:
WHERE column >= {startDateAtMidnight}
AND column < {dayAfterEndDateAtMidnight}
Example:
<!--- default both to something that is NOT a valid date --->
<cfparam name="url.start_date" default="">
<cfparam name="url.end_date" default="">
<!---
If at least ONE of the dates was supplied, apply
the desired defaults for missing values
--->
<cfif isDate(url.start_date) || isDate(url.end_date)>
<cfset url.start_date = isDate(url.start_date) ? url.start_date : "some default like 2012-01-01 here">
<cfset url.end_date = isDate(url.end_date) ? url.end_date : now()>
</cfif>
<cfquery ....>
SELECT ...
FROM ...
WHERE ...
<!--- apply the filter when both dates are populated. --->
<cfif isDate(url.start_date) and isDate(url.end_date)>
AND tslo.last_modified >= <cfqueryparam value="#url.start_date#" cfsqltype="cf_sql_date">
AND tslo.last_modified < <cfqueryparam value="#dateAdd('d', 1, url.end_date)#" cfsqltype="cf_sql_date">
</cfif>
</cfquery>
It might not be the cause, but you are mixing data types. This:
and <cfqueryparam value="#Trim(url.start_date)#" cfsqltype="cf_sql_date">
<= DATE_FORMAT(tslo.last_modified, '%Y-%m-%d')
will have a date on the left hand side of your comparison operator and a string on the right. Even if it runs without error, you might get unexpected results. As a minimum, remove the date_format function from the right hand side.
Then we have this:
AND DATE_FORMAT(tslo.last_modified, '%Y-%m-%d') <= DATE_FORMAT(NOW(), '%Y-%m-%d')
at least it's comparing a string to a string, but it's inefficient. In the overall scheme of things, maybe you want something like this:
and tslo.last_modified >=
<cfqueryparam value="#Trim(url.start_date)#" cfsqltype="cf_sql_date">
and tslo.last_modified =< now()