This question already has answers here:
coldfusion weird extra space
(3 answers)
Closed 8 years ago.
I have a CFC that returns a string containing part of a URL. I want to concatenate this to the end of the domain name of the site so it makes a fully qualified URL.
However, the ColdFusion is creating a space before the concatenation. Here is how my concatenation looks:
http://www.mywebsite.com#APPLICATION.MyCFC.GetURL(urlid = url.id)#
So we have two parts:
The domain part which is just http://www.mywebsite.com
The string that's returned from the CFC which is like this /products/20
However the final output ends up like this:
http://www.mywebsite.com /products/20
So for some reason it puts a space just before concatenating the string from the CFC. I have tried to put a Trim() around the CFC invokation but it doesn't do anything.
What I have also tried to do is put the string from the CFC in a variable like this <cfset myurl = #APPLICATION.MyCFC.GetURL(urlid = url.id)#. I then concatenated this variable to the domain like this: http://www.mywebsite.com/#url# and it works fine without adding any spaces.
Why is it doing this? I don't want to keep storing the output of the CFC in yet another local variable everytime I want to use it.
This is the code from the CFC (I've left out the database stuff that it does for sake of confidentially and clarity but its essentially just this):
<cffunction name="GetURL" access="public" returntype="string">
<cfargument name="urlid" required="yes">
<cfset var result="/products/#urlid#">
<cfreturn result>
</cffunction>
add output="false" to your <cffunction> (and <cfcomponent> if it is not an UDF) may solve your problem.
Related
This question already has an answer here:
ColdFusion: get url parameter by name
(1 answer)
Closed 6 years ago.
I would like to know how to get a query string from an url using coldfusion.
I have following url:
http://mypage.com/books/8540/index.cfm?current_book=215487
Now I would like to extract current_book=215487 in a var. The code below returns only the current URL.
<cfset currentURL = cgi.request_url/>
There is a scope that URL variables are stored called the URL scope (there is also one for FORM variables called FORM).
If you want to get it, you should make sure it is set, which you can do with a <cfparam> call:
<cfparam name="url.current_book" default="">
<cfset current_book = url.current_book>
Now you can use the current_book variable if you need to, or access the url.current_book variable directly like:
<cfoutput>
You chose #HTMLEditFormat(url.current_book)#
</cfoutput>
Which would output You chose 215487
I recently moved my code from CF9 to CF11 and I am having issues when I am trying to use serializeJSON. According to CF docs:
Starting from ColdFusion 11, the data type is preserved during the
code execution time for Query and CFCs.
SerializeJSON considers datatypes defined in the database for
serialization. If the database defines a column as a string, any
number inserted into the column will still be treated as a string by
SerializeJSON.
But I guess this is not the case....
When I am pulling data out of a varchar column in CF9 it comes out like this "docid":"123" which is what I want but in CF11 the same data look like this "docid":123 and is causing an issue with what I am trying to do.
To be more specific, my ids look like this 2001101009460111385185 which is longer than what javascript can accept and they get converted into scientific notation. With the old format I didn't have this issue because my ids were treated as a string which is what I want.
Note: my code is exactly the same on both versions of CF
Anyone had this issue before and HOW did you go around it?
Code Sample
I am calling this function via an AJAX call, this function returns an array with a struct in it. When I dump the return value after I serialize the result I can see a JSON object in my console but the quotes are missing from all the number values. In a test file I created a simple query and then I am serializing the results and everything looks good......
<cffunction name="locationData" returnformat="json" access="remote">
<cfargument name="locationid" required="yes" type="string">
<cfargument name="clientBrandid" required="yes" type="string">
<cfscript>
locationData = new mod_sigweb.components.xamplifierCFCs.location_info();
result = locationData.getLocation(locationid,clientBrandid);
</cfscript>
<cfdump var="#serializeJSON(result[1],'struct')#">
<cfabort>
<cfreturn #result#>
</cffunction>
The unfortunate workaround that I have had to use for this bug is to concatenate a space to the end of the value
<cfloop index="i" from="1" to="#ArrayLen(result)#">
<cfset result[i].docid = result[i].docid & " "/>
</cfloop>
and then the js has to be aware of this (I know, it's bad) and remove that trailing space.
I am using ColdFusion 8.0.1
I am working on an existing application that has thousands of pages. I am trying to include a library of new UDFs in my application.cfm file.
I addedd this line to application.cfm:
<!--- UDF library include --->
<cfinclude template="UDF/udf_library.cfm">
The UDF library includes other files that contain UDFs, like this:
<cfinclude template="udf_powerreview.cfm">
I have functions in the udf_powerreview.cfm file, such as:
// CREATE POWER REVIEWS SNIPPET
function createPRSnippet(Page_ID) {
LOCAL.Page_ID = ARGUMENTS.Page_ID;
if (isNumeric(LOCAL.Page_ID) && LOCAL.Page_ID > 0) {
LOCAL.Snippet = "<div class='pr_snippet_product'><script type='text/javascript'>var pr_snippet_min_reviews = 0; POWERREVIEWS.display.snippet(document, { pr_page_id : '#LOCAL.Page_ID#' });</script></div>";
} else {
LOCAL.Snippet = "";
}
return LOCAL.Snippet;
}
The debugging tool says that UDF/udf_library.cfm and udf_powerreview.cfm are being successfully included.
The problem is when I call the function in another page, I get an error that says that function doesn't exist. When I can copy the function and put it directly into the page that it is used in and it works just fine. And, I do not get the error "routines can not be declared twice".
In every site that I build, I create a udf_library.cfm or udf_library.cfc in the exact same manner. They always work fine.
What might prevent the functions from being available and accessed? Is there an application setting that needs to be set?
It's a page scope issue. Don't think of the Application.cfm as an include on all your pages, just know that it runs first. Somethings it initializes will carry over to your existing page scope and some things won't. Using an Application.cfc instead of an application.cfm takes care of much of the ambiguity.
To make your UDF's available to your whole application, I would suggest using a "Singleton" Design pattern. First take your UDF's and put them in a CFC format. This will make them more portable.
in your application.cfm you could put the following lines:
<cfif NOT isdefined('session.udf_powerreview') or isdefined('url.resetudf')>
<cfset session.udf_powerreview = createobject('Component','udf.udf_powerreview')/>
<!--- this 'udf.udf_powerreview' represents the physical path udf/udf_powerreview.cfc --->
</cfif>
I'm stuffing it in the session scope instead of the application scope, becuase you won't have an good way of resetting the application scope if you modify your UDF's.
Either way, once this is in your application.cfm you should be able to see your functions on any page.
<cfdump var="#session.udf_powerreview#">
Here is one strategy that I use. This basically calls the UDFs "on demand". It won't reimport the UDFs if it already exists. You do however have to have named arguments however, otherwise you'd have to strip out the UDFName out of the argument collection. I'm worried however that argument order might not be preserved, I haven't investigated that.
application.cfm
<cfapplication
name="udftest_001" />
<cffunction name="udf">
<cfargument name="udfname" type="string" required="true">
<cfif NOT isDefined(udfname)>
<cfinclude template='./udfs/#udfname#.cfm'>
</cfif>
<cfset tempfunc = variables[udfname]>
<cfreturn tempfunc(argumentCollection=arguments)>
</cffunction>
index.cfm
<cfoutput>
#udf(udfname='testUDF',firstname='John',lastname='Smith')#<br/>
#udf(udfname='testUDF',firstname='Betty',lastname='Ford')#<br/>
</cfoutput>
/udfs/testudf.cfm
<cfscript>
function testUDF() {
return 'Hello ' & arguments.firstname & ' #arguments.lastname#';
}
</cfscript>
I suspect something is up with relative paths.
Can you make "UDF" a mapping? Then you can do
<cfinclude template="/UDF/udf_library.cfm">
I created a simple custom tag which takes a string, replaces whitespace with "-" and "&" with "and" for a querystring (I don't want %20's and the like).
Anyways, it works fine, however my custom tag is creating a space before itself like so:
qsEncode.cfm: (custom tag)
<cfparam name="attributes.string" type="string" default="">
<cfset whitespace = Replace(attributes.string," ","-","all")>
<cfset ampersand = Replace(whitespace,"&","and","all")>
<cfoutput>#ampersand#</cfoutput>
The implementation of the tag:
">#getCategory.Name#
And the final output which is creating a space before the tag:
somepage.cfm?Page=%20Finance-and-Taxes
My custom tag isn't being passed a string that has whitespace prepended to it (and even if it was it would be replaced by the "-" character) so I don't understand why the tag is creating whitespace.
Note: I do realize I can include ?Page= inside my custom tag which would fix it, but I'm still curious as to why this is happening.
Your specific problem with extra space can likely be fixed by using:
<cfsetting enablecfoutputonly="true">
as the very first thing inside your custom tag (and setting it back to "false" at the end).
However, I would highly recommend replacing the functionality of the custom tag with an actual function -- either inline, or (preferably) within a cfc. Either way, you want something like this:
<cffunction name="qsEncode" output="false" returntype="string">
<cfargument name="str" type="string" required="true">
<cfset var whitespace = Replace(arguments.str," ","-","all")>
<cfset var ampersand = Replace(whitespace,"&","and","all")>
<cfreturn ampersand>
</cffunction>
Then you'd have:
#getCategory.Name#
For utility functions like these that don't maintain state, a quick solution (putting aside arguments as to the wisdom of singletons) is to set up a utility cfc, and store it as a singleton in the application scope. Instantiate the utility.cfc in the onApplicationStart handler of your Application.cfc. Then, throughout your application, you can do things like this:
application.utility.qsEncode('this');
application.utility.someOtherFunction('that');
application.utility.yetAnotherStringMangler('theother');
Ken is correct - the white space in your custom tag CFM is creating the extra space in it's output. And I recommend his answer (I prefer calling UDF functions in over custom tag CFMs... even better as a function in a CFC object over CFM).
But if you want to simply adjust your existing custom tag, use CFSILENT to stifle whitespace output (and assure no trailing whitespace after last tag in the file).
<cfsilent>
<cfparam name="attributes.string" type="string" default="">
<cfset whitespace = Replace(attributes.string," ","-","all")>
<cfset ampersand = Replace(whitespace,"&","and","all")>
</cfsilent><cfoutput>#ampersand#</cfoutput>
By default, ColdFusion passes simple types (like numeric, string, and GUID) by value to functions. I'd like to pass a simple type by reference.
I'm currently wrapping a simple value in a struct (they get passed by reference). This solves my problem but it is very ugly:
<!--- TheFunctionName---->
<cffunction name="TheFunctionName">
<cfargument name="OutVariable" type="struct">
<cfset OutVariable.ID = 5>
</cffunction>
<cfset OutVariable=StructNew()>
<cfset TheFunctionName(OutVariable)>
<!--- I want this to output 5--->
<cfoutput>#OutVariable.ID#</cfoutput>
I'd rather something like this:
<!--- TheFunctionName---->
<cffunction name="TheFunctionName">
<cfargument name="OutVariable" passbyref="true">
<cfset OutVariable = 5>
</cffunction>
<cfset TheFunctionName(OutVariable)>
<!--- I want this to output 5--->
<cfoutput>#OutVariable#</cfoutput>
AFAIK, there's no way to pass simple values by reference in ColdFusion. The only workaround I can think of is the one you're already using.
Instead, I would suggest trying to restructure your program to work with the grain of the language. In cases where there's only one simple value to "modify", you could just make your function return the new value, and call it like:
<cfset SomeVar = TheFunctionName(SomeVar)>
In cases where you're modifying multiple values, take a step back and think about whether it's possible to bundle those multiple values up into a CFC with your mutator functions becoming methods of the CFC. This could be clearer and more maintainable solution anyway.
You can arrange for the variables used outside and inside the function to be in a scope that exists in both code areas. For example, if you put a variable in the "session" or the "request" scope you will be able to access it from within the function. The changes made will persist.
Note that when you are doing this you aren't actually "passing" the variables to the function. The function just assumes the variable exists or creates it, depending on how you code it.
<cffunction name="TheFunctionName">
<cfset Request.StrVar = "inside function<br />" />
</cffunction>
<cfscript>
Request.StrVar = "outside function<br />";
WriteOutput(Request.StrVar);
TheFunctionName();
WriteOutput(Request.StrVar);
</cfscript>
About ColdFusion Scopes
If there is any doubt about the calling page declaring the variable in advance when it is required you'll have to do some legwork with the <cfparam> tag or IsDefined() function.
If you:
declare the function inside of a CFC
invoke the function using <cfinvoke>
You would be able to specify the <cfinvoke> parameter "returnvariable", and then output that variable however you like.
<cfinvoke component="this" method="TheFunctionName" returnvariable="blah">
<cfinvokeargument name="data" value="whatever" type="string">
<cfreturn data>
</cfinvoke>
<cfdump var="#blah#">
If you are writing everything in cfscript, then I would go with what SurroundedByFish said.