That title really isn't very clear, so let me explain a bit more about what this blog entry is about. A reader asked if it was possible to do pagination via Ajax (ie, each page of content is loaded via Ajax), but have the controls (the previous and next buttons) exist outside of the Ajax-loaded content. This is an interesting question. It is incredibly trivial to load content via Ajax with jQuery. My seven year old could do it in his sleep. But we need to find a way to handle showing, and hiding, the navigation controls. We also need to ensure those controls can correctly "drive" the content to handle paging. Like ColdFusion, jQuery provides many ways to solve a problem. This is just one example.
Yesterday I blogged about a proof of concept 911 viewer I built using CFMap and jQuery. The first example simply retrieved all of the 911 reports and mapped them at once. The second demo was more complex. This demo actually showed you map data from the beginning of the collection to the most recent report. Watch the video if that doesn't make sense. Let's look at how I built that demo. (Warning: I'm going to jump around a bit code wise but at the end I'll paste the entire template.)
Proof of Concept 911 Viewer
Jan 19
First, I began by looking at the reference guide for directions under Google Maps. It begins with the creation of a directions object. Once you have that, you can then load a query and have it auto-populate the results. And.... well that's it! You can tweak things up quite a bit as the docs show, but here is a quick example you can play with:
2
3 <html>
4
5 <head>
6 <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
7 <script>
8 $(document).ready(function() {
9
10 $("#doDirections").click(function() {
11 var youraddy = $.trim($("#youraddress").val())
12 if(youraddy == '') return
13 console.log('Directions from '+youraddy)
14 var mapOb = ColdFusion.Map.getMapObject("themap")
15 var dir = new GDirections(mapOb, document.getElementById('result'))
16 <cfoutput>
17 dir.load("from: "+youraddy +" to: #theAddress#")
18 </cfoutput>
19 console.log('done')
20 })
21 })
22 </script>
23 <style>
24 #result {
25 width:500px;
26 height: 500px;
27 overflow: auto;
28
29 }
30 </style>
31 </head>
32
33 <body>
34
35 <cfmap name="themap" centeraddress="#theAddress#" width="400" height="400" zoomlevel="9">
36 <p>
37 <form>
38 Your Address <input type="text" name="youraddress" id="youraddress" value="San Francisco, CA"><br/>
39 <input type="button" id="doDirections" value="Get Directions">
40 </form>
41 <p>
42
43 <div id="result"></div>
44
45 </body>
46 </html>
I'm going to jump around a bit here so please forgive me. (I find that the way I write CFML does not lead itself well to actually teaching or writing about it well!) The very first line hard coded an address. This would be the store or other location you want to display to your users. At the bottom of the script you can see where I use this within the CFMAP tag. Below it I've created a simple form. I hard coded in San Francisco to save myself some typing.
Now if we hop back to the top you can see my jQuery code. I've bound to the button click action. I get the address and ensure something is there. Once I have it then I get the map object (that line of code should be moved up and out of this event handler, I shouldn't be regrabbing it for every click). I then make a new instance of the GDirections object. I give it my map and a pointer to my div that will be used for the results. (jQuery provides a way to do that of course but I forgot and was in a rush!) Next I do the load operation. This takes a string of the form:
from: somelocation to: somelocation
For my demo, the to is hard coded and the from is based on your input. And that's it. The result will get dumped into my div. If I wanted to I could extract out individual bits of it but for now it works fine as is. You can demo this here: http://www.coldfusionjedi.com/demos/jan182010/test3.cfm One quick note - I warned folks this is a proof of concept so it shouldn't be used without more testing, but I want to point out one serious mistake that should be corrected. The jQuery document.ready event I use here can and probably will fire before the map is loaded. I should have used ColdFusion's ajaxLoad function to register the setup call. That's a 2 second fix but I wanted to make sure folks remembered that.
Yesterday a reader wrote me with an interesting question. He was using ColdFusion's Ajax controls to load content into a cfdiv. Within the content loaded via Ajax, he had a simple form with some checkboxes. He wanted to use jQuery to support a "Check All" button. For some reason though the event handler he used never worked. Let's take a look at his initial code.
CFMAP and Centering
Dec 27
For a while now I've had two line items in my "To write about" notebook. They concerned figuring out how to use CFMAP (and Google Maps in general) to center the map on an address. Out of the box you have an immediate address that acts as the center, but I wanted to see how the center could be changed post map load.
My first attempt was to figure out a way to center the map on an marker. I began with an extremely simple script:
2 <cfset p = "password">
3
4 <cfhttp method="post" url="http://127.0.0.1/CFIDE/services/upload.cfc?returnformat=json" result="result">
5 <cfhttpparam type="file" name="upload" file="/Users/ray/Documents/ColdFusion/ColdSpring_Reference.pdf">
6 <cfhttpparam type="formField" name="serviceusername" value="#u#">
7 <cfhttpparam type="formField" name="servicepassword" value="#p#">
8 <cfhttpparam type="formField" name="method" value="uploadForm">
9 </cfhttp>
10 <cfset res = deserializeJSON(result.filecontent)>
11 <cfdump var="#res#">
12
13 <cfhttp method="post" url="http://127.0.0.1/CFIDE/services/pdf.cfc?returnformat=json" result="result">
14 <cfhttpparam type="formField" name="serviceusername" value="#u#">
15 <cfhttpparam type="formField" name="servicepassword" value="#p#">
16 <cfhttpparam type="formField" name="method" value="extractImage">
17 <cfhttpparam type="formField" name="source" value="#res[1].value#">
18 </cfhttp>
19 <cfdump var="#deserializeJSON(result.filecontent)#">
Now that we have a pointer to the file we can use it with the PDF service. In this case I run the extractImage method. The result is a list of image URLs for each and every image from the PDF:
Pretty simple, right? While I can't imagine why you would use ColdFusion to post to another ColdFusion server to use CFaaS, you could if you wanted to. Mainly I imagine this example being useful if translated to another language, like PHP. (Just take the number of lines of code above and multiple by 4.)
For my second example, I did something a bit fancier. I used Aptana Studio to create a new HTML-based AIR application. This example makes use of the Image service and converts an image (specified by a URL) to grayscale:
Ok, not exactly rocket science, but not something you can easily do in HTML (as far as I know - I do know that CSS does some cool filtering so it may actually support this!). The code behind this is relatively simple:
2
3 <head>
4 <script src="lib/jquery/jquery-1.3.2.js"></script>
5 <script>
6 $(document).ready(function() {
7
8 $("#doit").click(function() {
9
10 $("#result").html("Working...")
11 var source = $("#imageurl").val()
12 source = $.trim(source)
13
14 $.getJSON("http://127.0.0.1/CFIDE/services/image.cfc?returnformat=json",
15 {method:"grayscale",serviceusername:"cfremoteuser1",
16 servicepassword:"password", source:source},function(data,status) {
17 $("#result").html("<img src='"+data+"'>")
18 })
19
20 })
21 })
22 </script>
23 <style>
24 body {
25 padding: 5px;
26 background-color: #33ff33;
27 font-family:"MS Sans Serif", Geneva, sans-serif;
28 }
29 </style>
30 </head>
31 <body>
32
33 <h1>jQuery CFaaS Demo</h1>
34
35 <p>
36 Enter an Image URL: <input type="text" id="imageurl"> <input type="button" id="doit" value="Make It Gray" >
37 </p>
38
39 <div id="result"></div>
40
41 </body>
42 </html>
My initial answer to this question was no. I knew that the ajaxImport tag supported a scriptSrc attribute. According to the docs, this specifies a folder, relative to the web root, where the relevant JavaScript files will be loaded. On a whim though, I tried a full path:So having common JavaScript files "in the cloud" and referencing them in your code as absolute urls is becoming more common. Is there a way to have CF point to the EXT-JS files hosted by a third party?
2 <script type="text/javascript" src="http://www.cnn.com/foo/ajax/package/cfajax.js"></script>
3 <script type="text/javascript" src="http://www.cnn.com/foo/ajax/yui/yahoo-dom-event/yahoo-dom-event.js"></script>
4 <script type="text/javascript" src="http://www.cnn.com/foo/ajax/yui/animation/animation-min.js"></script>
5 <script type="text/javascript" src="http://www.cnn.com/foo/ajax/ext/adapter/yui/ext-yui-adapter.js"></script>
6 <script type="text/javascript" src="http://www.cnn.com/foo/ajax/ext/ext-all.js"></script>
7 <script type="text/javascript" src="http://www.cnn.com/foo/ajax/package/cfwindow.js"></script>
8 <link rel="stylesheet" type="text/css" href="http://www.cnn.com/foo/ajax/resources/ext/css/ext-all.css" />
9 <link rel="stylesheet" type="text/css" href="http://www.cnn.com/foo/ajax/resources/cf/cf.css" />
John asks:
How would you go about dynamically adding and removing cfmapitems from a cfmap?
This was a question that came in yesterday. I fired off a quick reply because the answer was so simple, but I said I'd follow up with a proper example later. I wrote up a quick example and was ready to blog when I noticed the evil, mean, nasty part of his email "removing". Yeah.... that one word made me dig into code for an additional two hours trying to get it to work. I'm really upset now. Ok, I'm not. I freaking love solving problems. That's why I got into coding in the first place! Anyway, let's talk ColdFusion 9, maps, and markers.
Dale asks:
I want the user to be able to print a cfmap that is within a cfwindow. Is there a way to add a print button to a cfwindow or cfmap?
I had to dig a bit to find the answer, and of course as soon as I did, my buddy Todd Sharp pointed out multiple ways to make it better, but the answer is, yes, you can. Here is how I solved it.