how to access value of cfset into ajax function - coldfusion

I am new in ColdFusion.
I am trying to access ColdFusion value into ajax function.
<cfset lagtime=#data# />
<script type="text/javascript" language="JavaScript">
function test(){
var adata =<cfoutput>#lagtime#</cfoutput>;
alert(adata);
}
</script>
I want to access lagtime value into variable adata.
If anyone know please help me out.
Thanks

The problem that you may be running into is that the value contained inside your data parameter could be a string causing your javascript to break. Just in case I have wrapped the output in single quotes which tells javascript to treat your value as a string.
Also I am not sure what your HTML looks like. For completeness I have include a full working example. Also note that the lagtime variable is not really required.
<cfset data = "hello">
<cfoutput>
<html>
<head>
<script type="text/javascript" language="JavaScript">
function test()
{
var adata = '#data#';
alert(adata);
}
</script>
</head>
<body>
<input type="button" value="Execute Test" onclick="test();">
</body>
</html>
</cfoutput>
Also to be clear you are not accessing the coldfusion variable. What you are doing is creating the javascript dynamically using coldfusion. e.g. Thats why could can not assign a javascript variable to a coldfusion variable inside a cfml template.

If the data type is string then use:
var adata = "<cfoutput>#lagtime#</cfoutput>";

I would encourage using toScript() function to assign a ColdFusion variable to Javascript. It also supports conversion of complex data types such as Array, Structure and Query.
<cfset lagtime=#data# />
<script type="text/javascript" language="JavaScript">
<cfoutput>
function test(){
var #toScript(lagtime, "adata")#;
alert(adata);
}
</cfoutput>
</script>
To be clear, it does the same thing as dynamically declaring a javascript variable, but it takes out the worry of type matching and notation. You can forget about the notation and concentrate on your data. Imagine the pain, if this variable was a query or an array object.

Related

ColdFusion Dropbox - How to get the token from the response URI

I am trying to implement the OAuth with Dropbox from a ColdFusion application, and I managed how to call the Dropbox method to generate the access token, but... I don't know how to get the generated TOKEN from the response URI. I am getting something like this from Dropbox:
http://localhost/dropbox/generate_token.cfm#access_token=AAAAAAAAYVM_XdCYlbTz0gQOwQkWlg6TDXf84_5h4giikg6J-7Man&token_type=bearer&uid=267693&account_id=dbid%3AAABeDMm-BN0n1DofLZz9kPZAipnQ
How to I retrieve the URL variables in this case? I mean if I do a
<cfdump var="#URL#">
I am getting an empty struct. If I do a
<cfdump var="#CGI#">
I still don't see any of the URL retrieved parameters in the structure. How do I get the variables and their values from the Dropbox response?
UPDATED
At some point I thought I found a way to read the URL but now - for no reason - this doesn't work anymore! I didn't change anything but the solution below doesn't work anymore.
I can read the full URL with JavaScript using document.location but this means to do an extra submit to a ColdFusion page and I don't want to do this. I want to get the Dropbox token from the URL and save it to the database directly in this page...
Any new ideas please?
SOLUTION THAT SEEMED TO WORK AT SOME POINT ...
I found a way to get the URI string using this:
<cfset objRequest = GetPageContext().GetRequest().getParameterMap() />
<cfdump var="#objRequest#">
<cfoutput>
<cfloop collection="#objRequest#" item="i">
<p>
#i# - #objRequest[i][1]#
</p>
</cfloop>
</cfoutput>
From now on, I know how to get the values returned by Dropbox.
I found a way to get the returned parameters by reading the browser URL with JavaScript, so in two steps: first, parse and extract the full URL including the part after the # sign (I found this has a name and it is called the "URL fragment") and second, create a JavaScript form with parsed parameters and resubmitted to the server. Here is the code:
<cfparam name="FORM.action" default="">
<cfif FORM.action IS "save_token">
<cfdump var="#FORM#">
<cfelse>
<form name="main" id="main" method="post">
<input type="hidden" name="action" id="action" value="save_token">
</form>
<script type="text/javascript" language="javascript">
<!--
var parameters = window.location.hash.substr(1).split("&");
function addHidden(theForm, key, value) {
// Create a hidden input element, and append it to the form:
var input = document.createElement("input");
input.type = "hidden";
input.name = key;
input.value = value;
theForm.appendChild(input);
}
// Form reference:
var theForm = document.forms["main"];
for (var i=0; i<parameters.length; i++) {
// Add data:
addHidden(theForm, parameters[i].split("=")[0], parameters[i].split("=")[1]);
}
theForm.submit();
//-->
</script>
</cfif>

Extract URL from SCRIPT portion of HTML Code with RegEx

I have one URL which is inside a <script> tag and I need to extract that URL:
Using ReMatchNoCase(), I can find the script and place it in an array.
<SCRIPT LANGUAGE="JavaScript" > //alert("a chance stuff"); document.location.href="https://mypage.cfm"; </SCRIPT>
To extract the URL, I am using the following code
<cfset ulink = reMatchNoCase("<SCRIPT.*?>.*?</SCRIPT>", data)>
<cfset link = Replacenocase(Replace(listLast(ulink[1],'='),'"','','ALL'),';</script>','','all')>
This works, but is there a cleaner way to do this?
Because ReFind/NoCase() is not designed to return the actual substring, this is about as simple as you're going to get.
<cfset data='<SCRIPT LANGUAGE="JavaScript" > //alert("a chance stuff"); document.location.href="https://mypage.cfm"; </SCRIPT>'>
<cfset ulink = reMatchNoCase("<SCRIPT.*?>.*?</SCRIPT>", data)>
<cfset link = Rematchnocase("http[^""']*",ulink[1])>
<cfoutput>#link[1]#</cfoutput>
Which is a little simpler than what you're doing. Alternatively you could use Mid(ulink[1]...) but with subexpressions from a ReFindNoCase(), but it is also no simpler.
The regular expression I use to match the URL is very generic, but it should easily do for the task. It simply captures everything until it finds a quote or apostrophe.
I did also think of this
<cfset data='<SCRIPT LANGUAGE="JavaScript" > //alert("a chance stuff"); document.location.href="https://mypage.cfm"; </SCRIPT>'>
<cfset ulink = rereplacenocase(data,"[\s\S]*?(<script.*?>[\s\S]*?(http[^""']*)[\s\S]*?</script>)[\s\S]*","\2","ALL")>
<cfoutput>#ulink#</cfoutput>
which is possibly better, but it is so much nastier to read and is less reliable for dealing with multiple <script> tags if that should arise.
Personally, I'd go with the first route. With RegEx, sometimes the "lazier" you try to be, the shakier the whole thing becomes. It's best to define the best pattern you can to attain your goal and in ColdFusion, I believe the first route is the best route.
You can do the following:
<cfset data = '<SCRIPT LANGUAGE="JavaScript" > //alert("a chance stuff"); document.location.href="https://mypage.cfm"; </SCRIPT>' />
<cfset start = REFindNoCase("<script[^>]*>", data) />
<cfset match = REMatchNoCase("https?://[^'""]*(?=.*</script>)(?!.*<script>)", mid(data, start, len(data) - start + 1)) />
In the second line I am finding the position of the <script> open tag (even though not absolutely necessary for this particular piece of data). In the 3rd line I find any URLs within the <script> tag. I use positive lookahead to make sure that there is a </script> end tag following, and negative lookahead to make sure there is not another <script> tag.

Populating text input in Coldfusion

I'm trying to do the following (amongst many other attempts), and have validated that #myVar# holds data and is current in the scope, but nothing works. Any ideas how to populate a text input in Coldfusion? Many thanks in advance!
<cfoutput>#myVar#</cfoutput>
<script>document.getElementById("text1").value = #myVar# </script>
The easiest way is with the value attribute of an input tag.
<form>
<input name "fred" value="flinstone">
etc
If you want to populate it dynamically, use cfoutput.
<cfset myVar = "flinstone">
<cfoutput>
<form>
<input name "fred" value="#myVar#">
etc
or is that not the question?
Your closing </cfoutput> is too early, where you're trying to output the value inside your javascript should also be wrapped in the cfoutput.
<cfoutput>
#myVar#
<script>document.getElementById("text1").value = "#myVar#";</script>
</cfoutput>
Is your value a string or an integer? If its a string you will need wrap the value in quotes.
Additionally you will want to use the jsStringFormat() function to ensure any quotes are escaped.
<script>document.getElementById("text1").value = "#jsStringFormat(myVar)#"; </script>

How to structure a master page with coldfusion?

I have a small coldfusion section of our site that all uses similar js and css files and page structure. The code is currently repeated for each file, and I'd like to factor it out and set something up using a master page and templates.
Master.cfm page:
<!--- Master template, includes all necessary js and css files.
Expects following variables to be defined:
- pageName - name of the file to be loaded as the body of the page
- title - text to be used as the title of the page and as the header text in the header bar --->
<cfinclude template="_lockedPage.cfm" />
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>#title#</title>
... all script and css links here ...
<script type="text/javascript" src="js/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="js/jquery.mobile-1.3.2.js"></script>
... etc ...
</head>
<body>
<div data-role="page">
<div class="headerDiv" data-role="header" data-theme="b" data-position="fixed">
<a id="backButton" data-role="button" data-direction="reverse" data-rel="back" data-icon="arrow-l" data-iconpos="left" data-theme="a">Back</a>
<h1><cfoutput>#title#</cfoutput></h1>
Home
</div>
<div data-role="content" class="container">
<cfinclude template="#pageName#.cfm" />
</div>
</div>
</body>
</html>
Then a page example would be something like this. CustomerSearch.cfm:
<cfscript>
title = "Customer Search";
pageName = "_customer-search";
include "Master.cfm";
</cfscript>
And then I would need a _customer-search.cfm page that would include all the body content for the page.
This means that I would need 2 files for every page that we currently have - the outer page that defines the variable and includes the master page, and the template page that has the individual page content.
Is this a good logical structure? Is there anyway to improve it?
You have the right idea, but I think you'll end up with a lot of unnecessary files. You could instead create a header.cfm and a footer.cfm that contain your global HTML. Each page would include those files and the content would be written between.
<cfset title = "Customer Search">
<cfinclude template="global_header.cfm">
<!--- This will be the content of your page. --->
<cfinclude template="global_footer.cfm">
This file would be named customer_search.cfm. Anytime you update the header or footer, it's a global change.
If you have a lot of business logic and query code that needs to exist on multiple pages, you might look into using an MVC framework to help you organize and reuse code. I prefer ColdBox (try ColdBox Lite), but many people use Framework/1.
I found that using custom tags was another simple solution and in my opinion a better solution to creating a separate header.cfm and footer.cfm.
In master.cfm:
<cfif ThisTag.ExecutionMode EQ 'start'>
[HEADER]
<cfelse>
[FOOTER]
<cfif>
In each content page:
<cf_master>
[CONTENT GOES HERE]
</cf_master>
If you'd like to pass in variables to the master page simply add it as an attribute to the opening tag:
<cf_master Title="Content Title">
And make sure the attribute is specified in the master file:
<cfparam name="Attributes.Title" default=""/>
<head>
<title><cfoutput>#Attributes.Title#</cfoutput></title>
</head>
The key for me was understanding the ThisTag.ExectuionMode. If you use custom tags you can either use just one tag or use an opening and closing tag. If you use an opening and closing tag then you can choose to include some content in the opening tag <cf_master>, and other content in the closing tag </cf_master>. That is why you need the if/else condition in master.cfm. In this case it is useful because then you can include a HEADER in the opening tag and a FOOTER in the closing tag.
Also, in case this isn't obvious, when you call your custom tag, it should match the name of the file where the code is stored. In my case <cf_master> matches master.cfm.
I used this page as a tutorial for custom tags: https://www.petefreitag.com/item/64.cfm
The Application.cfc can be a great use for common page design. Basically have one template and inject the pages generated content. Dan Bracuk commented in the other solution about using the Application.cfc onRequestStart() and onRequestEnd() methods but I use it slightly differently. Here is my general setup:
Application.cfc
// This is <cfscript> but it could be regular CFML too
component {
public function onRequest( required string targetPage ) {
// Capture/buffer the requested pages output
savecontent variable='LOCAL.output' {
include ARGUMENTS.targetPage;
}
// Use the output as the page content
// if the page did not specify content
param string REQUEST.content = LOCAL.output;
// Inject the design template
// which should output the page content somewhere
include '/path/to/template.cfm';
}
}
template.cfm
<!DOCTYPE html>
<cfparam name="REQUEST.title" type="string" /><!--- required --->
<cfparam name="REQUEST.head" type="string" default="" />
<cfparam name="REQUEST.content" type="string" /><!--- required --->
<html>
<head>
<title><cfoutput>#REQUEST.title#</cfoutput></title>
<link rel="stylesheet" href="path/to/common.css" />
<script src="path/to/common.js"></script>
<cfoutput>#REQUEST.head#</cfoutput>
</head>
<body>
<header>...</header>
<cfoutput>#REQUEST.content#</cfoutput>
<footer>...</footer>
</body>
</html>
each-page.cfm
<cfset REQUEST.title = "My Page Title" />
<cfsavecontent variable="REQUEST.head">
<!-- page specific head elements here -->
</cfsavecontent>
<!-- Regular page code/HTML output here -->
<!--- or you could use another <cfsavecontent> block --->
<!--- to save specific output sections --->
<p>Hello World</p>
This way allows you to keep the template all within one file which is much easier when designing it in a WYSIWYG manor. It also allows each page to set variables used in the design template, since the requested page is executed before the design template is included.
And, there is no need to <cfinclude> templates on each page since Application.cfc onRequest() will get called for ALL pages by default. If there are .cfm pages which should NOT include the design template, such as PDF output, then you'll need to add some logic to just dump the output and not include the design template.

How can I send an array variable to a ColdFusion CFC remote method via ajax using jQuery?

I have a ColdFusion CFC function like this:
<cffunction access="remote" name="getResults"
returntype="struct"
returnformat="JSON"
output="no">
<cfargument name="q" required="true" type="array" />
...
</cffunction>
How do I call this function from jQuery? Neither form of array encoding by jQuery will get ColdFusion to see the value as array.
If you pass "q=a&q=b" (like with jQuery.ajaxSettings.traditional = true), the function will get the string "a,b", not an array. While splitting on comma may seem like a possibility, it will not work if one of the "q" values contains a comma. Also, ideally, the function on the server-side should not have to be aware of the problems of how to serialize the data over the wire, and should continue to take in an array.
If you pass "q[]=a&q[]=b" (the jQuery default), it will not map over to the "q" parameter. If you try to change the name of the "q" parameter to "q[]", the CFC will error out due to an invalid parameter name.
First thing to know is jQuery Ajax requests do not encode arrays so have you to use something else to encode the data (this is where jquery.JSON.js comes from referenced below). So with a the JSON encoded found there, I then figured out the correct syntax by working with cfajaxproxy and studying the URL it generates in Firebug:
http://localhost/remote.cfc?method=getResults&argumentCollection=%7B%22q%22%3A%5B1%2C2%5D%7D
Yes the "argumentcollection" approach is correct, and the variable "q" with a reference to an array is in there.
I used the following code as a test bed:
remote.cfc
<cfcomponent output="false">
<cffunction access="remote" name="getResults"
returntype="struct"
returnformat="JSON"
output="no">
<cfargument name="q" required="true" type="array" />
<cfreturn {a=1,b=2}>
</cffunction>
</cfcomponent>
remote.cfm to see how cfajaxproxy generates its url
<cfajaxproxy cfc="Remote" jsclassname="Remote">
<cfoutput>
<script language="javascript" type="text/javascript">
var oRemote = new Remote();
alert(oRemote.getResults([1,2]));
</script>
</cfoutput>
remote.html doing it with jQuery
<script language="javascript" src="http://code.jquery.com/jquery-1.4.3.min.js"></script>
<script language="javascript" src="jquery.JSON.js"></script>
<script language="javascript" type="text/javascript">
var argumentCollection = { q: [1,2] };
$.ajax({
url: 'remote.cfc',
data: {
method: 'getResults',
argumentCollection: $.JSON.encode(argumentCollection)
},
success: function(response) {
alert(response);
},
dataType: 'json'
});
</script>
Investigating this problem, I found the following blog post:
http://www.coldfusionjedi.com/index.cfm/2010/3/23/Using-jQuery-to-post-an-array-to-a-ColdFusion-Component - This suggested encoding the array as a JSON string, and then deserializing it inside the CFC method, with the unfortunate impact of requiring the CFC function to have to change to deal with JSON.
So I investigated further, and here's the best solution I have found so far.
By looking at the HTTP calls made when using cfajaxproxy, I discovered that you can send a single argumentCollection parameter as a JSON string to call the remote CFC method.
So the client side call looks something like this (using jquery-json plugin to do the serialization):
var params = {q: ['a', '1,2,3']};
$.getJSON('My.cfc?method=getResults', {argumentCollection: $.toJSON(params)}, function(data) {
// handle data
});
How about checking your values for commas and escaping them before passing to Coldfusion, then use ListToArray to convert and (if necessary) re-encode the commas?