Related
I have a cfc where i need t return the headers for the jqgrid for binding dynamically
i am trying to query the data like this:
colNames: ['ID', 'Institution Name', 'Display Name', 'Short Name', 'Board of Education', 'Scheme Name','Subscription Date'],
colModel: [
{ name: 'institutionid', sortable: true, },
{ name: 'institutionname', sortable: true },
{ name: 'displayname', sortable: true },
{ name: 'shortname' ,sortable: true},
{ name: 'supportedfield', sortable: true },
{ name: 'schemename', sortable: true },
{ name: 'subscriptionto', sortable: true}
]
i can easily get the colNames, but for colmodal how can i bring the elements of sort: true for all by default and format should be like arrayofstructs
Thanks
Query try
<cffunction name="headers" localmode="modern" access="remote" returnformat="json" hint="Handles the Functionality of returning the Table Headers">
<cfset columnsInfos = {}>
<cfset returnArray = []>
<cfset cList = QueryExecute("select top 1 * from mytable").columnList>
<cfset cListQueryObj = QueryNew(cList)>
<cfdump var="#cListQueryObj#" abort>
<cfset colNames = ListtoArray(cList)>
<cfloop query="#cListQueryObj#">
<cfset rowStruct = {}>
<cfloop list="#cList#" index="colname">
<cfset "rowStruct['#colname#']" = cListQueryObj[colname]>
</cfloop>
<cfset arrayAppend(returnArray,rowStruct)>
<cfdump var="#rowStruct#">
</cfloop>
<cfset columnsInfos["colModel"] = returnArray>
<cfset columnsInfos["colNames"] = colNames>
<cfreturn columnsInfos>
</cffunction>
Serializing a query object won't return the expected result. Since you are using the built-in returnFormat="json", the easiest (and probably only) approach is working with an array of structs, just like your JS example shows:
<cffunction name="headers" localmode="modern" access="public" returnformat="json" hint="Handles the Functionality of returning the Table Headers">
<!--- best practise: declare the returned scheme --->
<cfset result = {
"colNames": [],
"colModel": []
}>
<!--- get your table's columns (mockup) --->
<cfset columnList = "institutionid,institutionname,displayname,shortname,supportedfield,schemename,subscriptionto">
<!--- use the column names from your query? --->
<cfset result["colNames"] = listToArray(columnList)>
<!--- add an entry with "name" and "sortable" for every column --->
<cfloop list="#columnList#" index="columnName">
<cfset result["colModel"].add({
"name": columnName,
"sortable": true
})>
</cfloop>
<cfreturn result>
</cffunction>
Note that we are not calling serializeJSON on the result, because returnFormat="json" will already do that for us. Regarding your colNames: Your JS example uses mapped column names, not dynamic ones as shown in your code and the code above. You might want to make them either static or map them yourself.
I like Alex's approach, but I like cfscript better. I also like localized variables.
<cfscript>
/**
* #hint Handles the Functionality of returning the Table Headers
* #output false
* #returnFormat JSON
*/
public any function headers() {
// best practise: declare the returned scheme
var result = {
"colNames": [],
"colModel": []
};
// get your table's columns (mockup)
var columnList = "institutionid,institutionname,displayname,shortname,supportedfield,schemename,subscriptionto";
// use the column names from your query?
result.colNames = listToArray(columnList);
// add an entry with "name" and "sortable" for every column
for (var columnName in columnList) {
result.colModel.add({
"name": columnName,
"sortable": true
});
}
return result;
}
writedump(headers);
writedump(headers());
</cfscript>
Function signature
Function results
Also see
JSON response using cfscript function
I have an array "varray" which needs to be split into four structures. The first of each four elements should be in structure 1, the second in structure 2, etc. I have some working code to do this, but it feels to me like there should be a less cumbersome way. Here is the code:
<cfset xord = StructNew()>
<cfset xsort = StructNew()>
<cfset xsel = StructNew()>
<cfset xmer = StructNew()>
<cfloop from = '1' to = "#ArrayLen(varray)#" index = 'i'>
<cfset fieldname = farray[i]> <!---farray previously defined --->
<cfset val = varray[i]> <!---varray previously defined --->
<cfset j = i%4>
<cfif j EQ 1>
<cfset xord[fieldname] = val>
<cfselseif j EQ 2>
<cfset xsort[fieldname]= val>
<cfelseif j EQ 3>
<cfset xsel[fieldname] = val>
<cfelseif j EQ 0>
<cfset xmer[fieldname] = val>
</cfif>
</cfloop>
Can anyone suggest a better way to do this?
It's been ages i did some CF, but a tag based approach by making use of local scope:
<cfset keys = ['xord', 'xsort', 'xsel', 'xmer'] />
<cfset farray = ['f1','f2','f3','f4','f5','f6','f7','f8']>
<cfset varray = ['v1','v2','v3','v4','v5','v6','v7','v8']>
<cfloop from="1" to="#ArrayLen(varray)#" index="i">
<cfset local[keys[i%4+1]][farray[i]] = varray[i]>
</cfloop>
<cfdump var="#xord#" />
<cfdump var="#xsort#" />
<cfdump var="#xsel#" />
<cfdump var="#xmer#" />
Now you have xord, xsort, xsel and xmer filled with the right key-value pairs within your local scope.
How about cfscript?
<cfscript>
function groupByOp(values, fieldnames) {
var ops = ['mer', 'ord', 'sort', 'sel'];
var byOp = {};
arrayEach(values, function (val, i) {
byOp["x#ops[i % 4 + 1]#"][fieldnames[i]] = val;
});
return byOp;
}
</cfscript>
This makes use of the fact that CF will automagically create structs when you mention a non-existing member.
Test:
<cfset v = ListToArray('1,2,3,4,5,6')>
<cfset f = ListToArray('a,b,c,d,e,f')>
<cfoutput>
<pre>#SerializeJSON(groupByOp(v, f))#</pre>
</cfoutput>
outputs
{
"xsel": {
"c": "3"
},
"xord": {
"e": "5",
"a": "1"
},
"xsort": {
"b": "2",
"f": "6"
},
"xmer": {
"d": "4"
}
}
(You didn't mention your version, so I don't know if you have access to newer functions like array each(). Keep in mind there's slicker options in newer versions)
Instead of creating separate variables, create a single structure containing the 4 variables, and an array of names. Then use the array and MOD to populate the substructures. Note, the example below creates the subsubstructures up front to ensure they always exist - even if the field/value arrays are empty or contain less than 4 elements.
TryCF.com Example
<cfset farray = ["A","B","C","D","E","F","G","Q","T"]>
<cfset varray = ["11","22","33","RR","55","NN","77","68","46"]>
<cfset data = {xOrd={},xSort={},xSel={},xMer={}}>
<cfset names = ["xOrd","xSort","xSel","xMer"]>
<cfloop from="1" to="#ArrayLen(varray)#" index="i">
<cfset fieldName = farray[i]>
<cfset fieldValue = varray[i]>
<cfset structName = names[i%4+1]>
<cfset data[structName][fieldName] = fieldValue>
</cfloop>
The substructures can be accessed through the parent, data.
<cfdump var="#data.xOrd#" label="data.xOrd">
<cfdump var="#data.xSort#" label="data.xSort">
<cfdump var="#data.xSel#" label="data.xSel">
<cfdump var="#data.xMer#" label="data.xMer">
Another couple of approaches.
I wouldn't necessarily say that these are better, but just different:
Requires field array length to match value array length
<cfset farray = ['field1','field2','field3','field4','field5']>
<cfset varray = ['apple','orange','pear','kiwi','pineapple']>
<cfset xord = {}>
<cfset xsort = {}>
<cfset xsel = {}>
<cfset xmer = {}>
<cfloop from="1" to="#ArrayLen(varray)#" index="i">
<cfset j =
((i%4 EQ 1) ? (StructInsert(xord,farray[i],varray[i])):
((i%4 EQ 2) ? (StructInsert(xsort,farray[i],varray[i])):
((i%4 EQ 3) ? (StructInsert(xsel,farray[i],varray[i])):
((i%4 EQ 0) ? (StructInsert(xmer,farray[i],varray[i])): 0))))>
</cfloop>
<cfdump var="#xord#" />
<cfdump var="#xsort#" />
<cfdump var="#xsel#" />
<cfdump var="#xmer#" />
OR:
<cfloop from="1" to="#ArrayLen(varray)#" index="i">
<cfswitch expression="#i%4#">
<cfcase value="0">
<cfset xmer[farray[i]] = varray[i]>
</cfcase>
<cfcase value="1">
<cfset xord[farray[i]] = varray[i]>
</cfcase>
<cfcase value="2">
<cfset xsort[farray[i]] = varray[i]>
</cfcase>
<cfcase value="3">
<cfset xsel[farray[i]] = varray[i]>
</cfcase>
</cfswitch>
</cfloop>
<cfdump var="#xord#" />
<cfdump var="#xsort#" />
<cfdump var="#xsel#" />
<cfdump var="#xmer#" />
Field array length does not have to match value array length
<cfset farray = ['field1','field2','field3','field4']>
<cfset varray = ['apple','orange','pear','kiwi','pineapple']>
<cfset xord = {}>
<cfset xsort = {}>
<cfset xsel = {}>
<cfset xmer = {}>
<cfloop from="1" to="#ArrayLen(varray)#" index="i">
<cfset j =
((i%4 EQ 1 AND ArrayIsDefined(farray,i)) ? (StructInsert(xord,farray[i],varray[i],true)) :
((i%4 EQ 2 AND ArrayIsDefined(farray,i)) ? (StructInsert(xsort,farray[i],varray[i],true)) :
((i%4 EQ 3 AND ArrayIsDefined(farray,i)) ? (StructInsert(xsel,farray[i],varray[i],true)) :
((i%4 EQ 0 AND ArrayIsDefined(farray,i)) ? (StructInsert(xmer,farray[i],varray[i],true)) : 0))))>
</cfloop>
<cfdump var="#xord#" />
<cfdump var="#xsort#" />
<cfdump var="#xsel#" />
<cfdump var="#xmer#" />
OR:
<cfloop from="1" to="#ArrayLen(varray)#" index="i">
<cfswitch expression="#i%4#">
<cfcase value="0">
<cfset (ArrayIsDefined(farray,i) ? (StructInsert(xmer,farray[i],varray[i],true)) : 0)>
</cfcase>
<cfcase value="1">
<cfset (ArrayIsDefined(farray,i) ? (StructInsert(xord,farray[i],varray[i],true)) : 0)>
</cfcase>
<cfcase value="2">
<cfset (ArrayIsDefined(farray,i) ? (StructInsert(xsort,farray[i],varray[i],true)) : 0)>
</cfcase>
<cfcase value="3">
<cfset (ArrayIsDefined(farray,i) ? (StructInsert(xsel,farray[i],varray[i],true)) : 0)>
</cfcase>
</cfswitch>
</cfloop>
<cfdump var="#xord#" />
<cfdump var="#xsort#" />
<cfdump var="#xsel#" />
<cfdump var="#xmer#" />
I have this function to generate slugs in Coldfusion:
<cffunction name="generateSlug" output="false" returnType="string">
<cfargument name="str">
<cfargument name="spacer" default="-">
<cfset var ret = "" />
<cfset str = lCase(trim(str)) />
<cfset str = reReplace(str, "[àáâãäå]", "a", "all") />
<cfset str = reReplace(str, "[èéêë]", "e", "all") />
<cfset str = reReplace(str, "[ìíîï]", "i", "all") />
<cfset str = reReplace(str, "[òóôö]", "o", "all") />
<cfset str = reReplace(str, "[ùúûü]", "u", "all") />
<cfset str = reReplace(str, "[ñ]", "n", "all") />
<cfset str = reReplace(str, "[^a-z0-9-]", "#spacer#", "all") />
<cfset ret = reReplace(str, "#spacer#+", "#spacer#", "all") />
<cfif left(ret, 1) eq "#spacer#">
<cfset ret = right(ret, len(ret)-1) />
</cfif>
<cfif right(ret, 1) eq "#spacer#">
<cfset ret = left(ret, len(ret)-1) />
</cfif>
<cfreturn ret />
</cffunction>
and then i am calling it using this:
<cfset stringToBeSlugged = "This is a string abcde àáâãäå èéêë ìíîï òóôö ùúûü ñ año ñññññññññññññ" />
<cfset slug = generateSlug(stringToBeSlugged) />
<cfoutput>#slug#</cfoutput>
But this is output me this slug:
this-is-a-string-abcde-a-a-a-a-a-a-e-e-e-e-i-i-i-i-o-o-o-o-u-u-u-u-n-a-no-n-n-n-n-n-n-n-n-n-n-n-n-n
it seems that all the accented characters are correctly replaced but this function is inserting a '-' after replacing them. Why?
Where is the error?
PD: i am expecting this output:
this-is-a-string-abcde-aaaaaa-eeee-iiii-oooo-uuuu-n-ano-nnnnnnnnnnnnn
Thanks.
Does this work for you? (I've adapted a similar script that we use internally.) I believe that we used this with ColdFusion 8 as we are still use it w/CF9.
<cffunction name="generateSlug" output="false" returnType="string">
<cfargument name="str" default="">
<cfargument name="spacer" default="-">
<cfset var ret = replace(arguments.str,"'", "", "all")>
<cfset ret = trim(ReReplaceNoCase(ret, "<[^>]*>", "", "ALL"))>
<cfset ret = ReplaceList(ret, "À,Á,Â,Ã,Ä,Å,Æ,È,É,Ê,Ë,Ì,Í,Î,Ï,Ð,Ñ,Ò,Ó,Ô,Õ,Ö,Ø,Ù,Ú,Û,Ü,Ý,à,á,â,ã,ä,å,æ,è,é,ê,ë,ì,í,î,ï,ñ,ò,ó,ô,õ,ö,ø,ù,ú,û,ü,ý, ,&", "A,A,A,A,A,A,AE,E,E,E,E,I,I,I,I,D,N,O,O,O,O,O,0,U,U,U,U,Y,a,a,a,a,a,a,ae,e,e,e,e,i,i,i,i,n,o,o,o,o,o,0,u,u,u,u,y, , ")>
<cfset ret = trim(rereplace(ret, "[[:punct:]]"," ","all"))>
<cfset ret = rereplace(ret, "[[:space:]]+","!","all")>
<cfset ret = ReReplace(ret, "[^a-zA-Z0-9!]", "", "ALL")>
<cfset ret = trim(rereplace(ret, "!+", arguments.Spacer, "all"))>
<cfreturn ret>
</cffunction>
<cfset stringToBeSlugged = "This is a string abcde àáâãäå èéêë ìíîï òóôö ùúûü ñ año ñññññññññññññ" />
<cfoutput>"#stringToBeSlugged# = #generateSlug(stringToBeSlugged)#</cfoutput>
Support for more International Character
If you want to widen your support for international characters, you could use ICU4J (java) and Paul Hastings' Transliterator.CFC to transliterate all of the characters and then replace any remaining spaces, dashes, slashes, etc with dashes.
https://gist.github.com/JamoCA/ec4617b066fc4bb601f620bc93bacb57
http://site.icu-project.org/download
After installing both, you can convert non-Latin characters by identifying the language id (to be converted to) and pass the string to be converted:
<cfset Transliterator = CreateObject("component","transliterator")>
<cfoutput>
<cfloop array="#TestStrings#" index="TestString">
<h3>TestString = "#TestString#"</h3>
<blockquote>
<div>CFC-1 = #Transliterator.transliterate('Latin-ASCII', TestString)#</div>
<div>CFC-2 = #Transliterator.transliterate('any-NFD; [:nonspacing mark:] any-remove; any-NFC', TestString)#</div>
</blockquote>
<hr>
</cfloop>
</cfoutput>
<h2>Available Language IDs</h2>
<cfdump var="#Transliterator.getAvailableIDs()#" label="Language IDs">
I have a txt file and would like to order all the rows according to a value in each row.
What is the best and fastest possible way to achieve this?
Below is the code that I use to compile my txt documents:
<!---CSV FILE--->
<cffile action="read" file="C:/ColdFusion10/cfusion/wwwroot/kelly2/debitorders.csv" variable="csvfile">
<cfoutput>
<!---LOOP THROUGH CSV FILE--->
<cfloop index="index" list="#csvfile#" delimiters="#chr(10)##chr(13)#">
<!---SET VALUES--->
<cfset accountholder = "#listgetAt('#index#',1)# #listgetAt('#index#',2)#">
<cfset accountholderlname = "#listgetAt('#index#',2)#">
<cfset accountnumber = "#listgetAt('#index#',3)#">
<cfset accounttype = "#listgetAt('#index#',4)#">
<cfset bankname = "#listgetAt('#index#',5)#">
<cfset branch = "#listgetAt('#index#',6)#">
<cfset amount = "#listgetAt('#index#',7)#">
<cfset date = "#listgetAt('#index#',8)#">
<!---SET INITIAL--->
<cfset initial = "#left(accountholder,1)#">
<!---SET LAST NAME--->
<cfset lname_final = "#replace("#accountholderlname#"," ","","all")#">
<!---GET AND SET ACC TYPE--->
<cfif accounttype eq "cheque">
<cfset accounttype_final = "CH">
<cfelseif accounttype eq "savings">
<cfset accounttype_final = "SAV">
<cfelseif accounttype eq "credit">
<cfset accounttype_final = "CR">
<cfelse>
<cfset accounttype_final = "OTH">
</cfif>
<!---SET AMOUNT--->
<cfset amount_final = #round(amount * 100)#>
<cfset amount_final = #NumberFormat(amount_final,"0000000")#>
<!---SET DATE--->
<cfset date_final = "#DateFormat(Date,"ddyyyymm")#">
<!---TRIM VALUES--->
<cfset initial = "#Left(initial, 1)#">
<cfset lname_final = "#Left(lname_final, 14)#">
<cfset accountnumber = "#Left(accountnumber, 13)#">
<cfset accounttype_final = "#Left(accounttype_final, 3)#">
<cfset branch = "#Left(branch, 9)#">
<cfset amount_final = "#Left(amount_final, 7)#">
<cfset date_final = "#Left(date_final, 8)#">
<!---SET STRING LENGTH FOR EACH--->
<cfset initial = "#LJustify(initial, 1)#">
<cfset lname_final = "#LJustify(lname_final, 15)#">
<cfset accountnumber = "#LJustify(accountnumber, 14)#">
<cfset accounttype_final = "#LJustify(accounttype_final, 3)#">
<cfset branch = "#LJustify(branch, 10)#">
<cfset amount_final = "#LJustify(amount_final, 7)#">
<cfset date_final = "#LJustify(date_final, 8)#">
<!---SET TOTAL STRING--->
<cfset total_string = "#initial##lname_final##accountnumber##accounttype_final##branch##amount_final##date_final#">
<pre>
#accountholder#<br>
#accountnumber#<br>
#accounttype#<br>
#bankname#<br>
#branch#<br>
#amount#<br>
#date#<br>
#initial#<br>
#lname_final#<br />
#accounttype_final#<br>
#amount_final#<br />
#date_final#<br>
123456789012345678901234567890123456789012345678901234567890<br />
#total_string#<br>
<br />
<br />
</pre>
<!---IF FILE FOR BANK EXISTS--->
<cfif FileExists(ExpandPath("#listgetAt('#index#',5)#.txt"))>
<!---READ EXISTING FILE HEADER--->
<cffile action="read" file="C:/ColdFusion10/cfusion/wwwroot/kelly2/#bankname#.txt" variable="bankheader">
<!---SPLIT UP THE HEADER TO ADD NEW VALUES ONTO IT--->
<cfset numericvalue = listfirst(bankheader,chr(13))>
<cfset numericvalue = #Right(numericvalue, 13)#>
<cfset RecordCountvalue = #Left(numericvalue, 3)#>
<cfset RecordCountvalue = #RecordCountvalue# + 1>
<cfset RecordCountvalue = #NumberFormat(RecordCountvalue,"000")#>
<cfset RecordCountvalue = #Left(RecordCountvalue, 3)#>
<cfset RecordCountvalue = #RJustify(RecordCountvalue, 3)#>
<cfset TotalRecordvalue = #Right(numericvalue, 10)#>
<cfset TotalRecordvalue = (#TotalRecordvalue# + #amount#) * 100000>
<cfset TotalRecordvalue = #NumberFormat(TotalRecordvalue,"0000000000")#>
<cfset TotalRecordvalue = #Left(TotalRecordvalue, 10)#>
<cfset TotalRecordvalue = #RJustify(TotalRecordvalue, 10)#>
<!---SET HEADER FOR FILE--->
<cfset fileheader_bank = "#UCase(bankname)#">
<cfset fileheader_bank = "#Left(fileheader_bank, 15)#">
<cfset fileheader_bank = "#LJustify(fileheader_bank, 16)#">
<cfset newfile_header = "#fileheader_bank##RecordCountvalue##TotalRecordvalue#">
<pre>
#numericvalue#<br />
#RecordCountvalue#<br />
#TotalRecordvalue#<br />
#newfile_header#
</pre>
<!---APPEND FILE AND ADD UPDATED HEADER--->
<cfset bankheader = listSetAt(bankheader,1,"#newfile_header#","#chr(13)#")>
<cffile action="write"
fixnewline="no"
addnewline="no"
file="#getDirectoryFromPath(getTemplatePath())#/#listgetAt('#index#',5)#.txt"
output="#bankheader#">
<!---APPEND FILE AND ADD NEW ENTRY--->
<cffile action = "append"
fixnewline="no"
file = "C:/ColdFusion10/cfusion/wwwroot/kelly2/#listgetAt('#index#',5)#.txt"
output = "#total_string#">
<!---IF FILE FOR BANK DOES NOT EXIST--->
<cfelse>
<!---SET HEADER FOR FILE--->
<cfset fileheader_bank = "#UCase(bankname)#">
<cfset fileheader_bank = "#Left(fileheader_bank, 15)#">
<cfset fileheader_bank = "#LJustify(fileheader_bank, 16)#">
<cfset newfile_header = "#fileheader_bank#001000#amount_final#">
<!---CREATE NEW FILE WITH BANK NAME--->
<cffile action = "write"
fixnewline="no"
file = "C:/ColdFusion10/cfusion/wwwroot/kelly2/#listgetAt('#index#',5)#.txt"
output = "#newfile_header#">
<!---APPEND FILE AND ADD NEW ENTRY--->
<cffile action = "append"
fixnewline="no"
file = "C:/ColdFusion10/cfusion/wwwroot/kelly2/#listgetAt('#index#',5)#.txt"
output = "#total_string#">
</cfif>
</cfloop>
</cfoutput>
I am not sure if it would be better if I start using an Array to do this, if so please advise.
I am not sure if it is possible to check as I insert each row to insert it into the correct place, I have never heard of this before.
I could also loop through the txt files at the end of the process if need be.
Read the csv file using cfhttp. The name attribute creates a query object. You can use Q of Q to do your sort and then carry on.
The details are in the documentation for cfhttp.
Given the following list (#oldList#):
category1_item1, category1_item2, category2_item1, category3_item1, category3_item2"
How can I create the following list (#newList#)?:
category1[item1&item2],category2[item1],category3[item1&item2]?
This is what I have so far:
<cfset newList = "">
<cfset category = "">
<cfloop list="#oldList#" index="listElement">
<cfset endPos = find("_", listElement)>
<cfset listElementCategory = left(listElement, endPos)>
<cfset listElementItem = replace(listElement, listElementCategory, "")>
<cfif listElementCategory is not category>
<cfset modifiedElement = replace(listElementCategory, "_", "") & "[" & listElementItem>
<cfelse>
<cfset modifiedElement = "&" & listElementItem>
</cfif>
<cfset category = listElementCategory>
<cfset newList = newList & modifiedElement>
</cfloop>
This code results in:
category1[item1&item2category2[item1category3[item1&item2
I just can't figure out how to close each "grouping" of items with "],".
<cfset newList = "">
<cfset category = "">
<cfloop list="#oldList#" index="listElement">
<cfset endPos = find("_", listElement)>
<cfset listElementCategory = left(listElement, endPos)>
<cfset listElementItem = replace(listElement, listElementCategory, "")>
<cfif listElementCategory is not category>
<cfif category is not "">
<!--- category has changed and this isn't the first record, so close previous category --->
<cfset newList = newList & "],">
</cfif>
<cfset modifiedElement = replace(listElementCategory, "_", "") & "[" & listElementItem>
<cfelse>
<cfset modifiedElement = "&" & listElementItem>
</cfif>
<cfset category = listElementCategory>
<cfset newList = newList & modifiedElement>
</cfloop>
Note I just added this block:
<cfif category is not "">
<!--- category has changed and this isn't the first record, so close previous category --->
<cfset newList = newList & "],">
</cfif>
Edit:
Almost forgot the end of the loop! After the </cfloop> close the brackets like:
<cfif category is not "">
<!--- close the final bracket since we have at least one record --->
<cfset newList = newList & "]">
</cfif>