Over the past few days, I've noticed an increase in questions about using the new AJAX capabilities of ColdFusion 8. This is great, it means people are playing with the new version. The AJAX functionality it brings to the table are quite amazing, and it makes using AJAX a snap.

However, once people have the CF8 AJAX elements talking to the server, some confusion seems to arise. I believe this confusion is coming from a misunderstanding of the two types of AJAX requests. I see AJAX used in two ways, and how you want to interact with the server depends on what you need to do.

First there are AJAX data requests. These are requests for pure data, to be used when populating a select box, grid, etc. There is no display content here. In this case, I don't think it makes sense to try and send requests to your application controller (such as Fusebox). The UI Controller frameworks are first and foremost meant to generate content: images, tables, styles, text, etc. So when your AJAX control just needs data, bypass the UI Controller. By the way, this is also the case when the request is for Flash Remoting or a web service. For AJAX data requests, the following image shows the sequence I follow:

Second, there are AJAX content requests. These are requests for actual display elements that will be used to populate a div or an AJAX tab panel. For these requests, it does make perfect sense to go through the UI Controller. Even better, if you use a framework that supports the idea of content variables, and you are using them in your application, your work is already done. It is easy to respond to the AJAX request by rendering a small bit of content, suppressing your global page layout, and returning that content to be injected into the div or tab. CF8 makes this very easy with the new ColdFusion.navigate() JavaScript function, or by using url binding in a cfdiv. For AJAX content requests, the following image shows the sequence I would follow:

Hopefully this explains the different ways you would interact with the server depending on what you're using AJAX for. Ideas or comments welcome, as always.

Comments Comments (23) | del.ico.us del.icio.us | Digg It! Digg It! | Linking Blogs Linking Blogs | 11889 Views

Comments

  • # Posted By Tony Brandner | 7/25/07 3:28 PM

    So true. You summarize so well my thoughts on the types of Ajax calls. Thanks for a great inspiring article!

  • # Posted By Brian Klaas | 7/25/07 5:01 PM

    A question for you, Brian: If you're operating under your currently running application, you most likely have all the authentication and request filtering code already in place and don't have to worry about handling that via tokens or some other mechanism if you're instantiating a remote facade separately. Why not direct the data calls through the controllers in M2, MG, or Fusebox in this case? If you've already set up remote proxies via ColdSpring in the overall app startup (and implented those cool enhancements you've been showing off to the proxy creation for AJAX apps), it seems like there's even less work to do and it would make more sense to run through the controllers.

    Am I missing something (which wouldn't be a big surprise)?

  • # Posted By Brian | 7/25/07 5:40 PM

    You may have authentication code, but it would (should?) be in a CFC as well (a SecurityService). And since your remote proxy has access to any application-scoped CFCs, as well as the session scope, it can leverage the same authentication that the base application uses.

    Or even better, the whole system could be using AOP to enforce security. But that's a separate discussion.

    The point is, your remote facade can leverage all the same logic that the rest of the application does. It can get references to your service CFCs from ColdSpring (or your application scope if you aren't using ColdSpring). It can access the session to check user privileges. There's really no extra work involved. Make sense?

  • # Posted By Aaron Roberson | 7/26/07 1:37 PM

    Brian,

    Thanks for the clear delineation. I have been doing a lot of the latter.

    Could you post a snippet of code exemplifying step 1 of the data request? I'm curious as to how you do the CFC binding (are your CFC's remote and you do the equivalent of invoking a CFC with a url...?).

  • # Posted By Brian | 7/26/07 2:08 PM

    The binding in CF8 is simply:

    <cfselect name="mediaid"
    bind="cfc:art.getMedia()"
    bindonload="true"
    value="MediaID"
    display="MediaType" />

    which would populate the select box with the results of the getMedia() method call on your Art CFC. Yes, the method has to be set to "remote".

    You can also do this with the new CF8 cfajaxproxy tag in CF8.

  • # Posted By Aaron Roberson | 7/26/07 6:01 PM

    Got it!

    Do you know what that would look like with prototype (I'm on BD 7, but I don't think I would use the built in AJAX controls I were on CF8 anyways)? Not the select part, but the AJAX call to a CFC?

  • # Posted By Brian | 7/26/07 6:05 PM

    I don't use Prototype for AJAX stuff so I don't know the actual syntax. But you'd have to manually do the work of creating an HTTP request to the target CFC in the format:

    http://www.site.com/mycfc.cfc?method=yourmethod&am...

    Your JavaScript would need to build up a URL like this. Also, your CFC would need to return results in JSON or WDDX format, and then you'd need to handle translating whatever was returned into something your JavaScript callback hander could use. Lastly, you'd need to write JavaScript to inject the returned data into your form control. This is all possible obviously, but without the handy stuff in CF8 it's going to be a lot more steps.

  • # Posted By Rob Gonda | 7/26/07 10:16 PM

    Brian, this is great! I've been getting the same question and I replied over pownce a few days ago (been meaning to blog it: http://pownce.com/cfsilence/notes/290217/).

    I couldnt have said it better myself... awesome post.

  • # Posted By Simon Green | 7/27/07 7:55 AM

    Brain,

    I kicked of a post on the yahoo Fusebox(FB) message board about problems I was having connecting my front end dsp pages to my backend CFC's taking advantage of the new CF8 Ajax features, while all going though FB. My initial problem was that I could not get the related drop down list I was working on to function with CF8's Ajax functionality, most like a bug in my code, but my post raised another interesting topic which is the source of this post/discussion.

    In my company we use fusebox to talk to our backend CFC's, all information ie query's, objects etc. are passed though FB to our dsp page. All the developers working on a project understand this and use FB for both Ajax and Postback data request. To me this seems nice and clean as there is one way for getting acces to data Another reason i like this is that we have security built into the circuits of FB that control access (maybe not the best solution). So we don't need to implement security anywhere else. In your post you say that for simple data calls don't use your controller, but for HTML returned via Ajax do, To me this over complicates if from a team point of view, it easier for me to enforce that all calls go though the controller, rather than saying if you are returning queries do it this way if you need to return html do it this.

    I am defiantly not saying my suggestion is correct, I'm fairly new to both CF, FB and the MVC approach of web development i just need to understanding my own head why pushing everything though the controller is not the cleanest way to do it

    Cheers

    Simon

  • # Posted By Brian | 7/27/07 11:33 AM

    Simon, this seems to be what most people initially think. Also, of course it's easy to talk about the "best" way to do something, but as always the best way is the way that works for you right now! However, I do believe there are definite reasons why you don't want to go through the controller for data requests.

    First it is essential that you understand the difference between a request for data (a query) and a request for content (an HTML table). The HTML request should go through Fusebox; that is what it is for, to build and return HTML results. That is probably pretty self explanatory.

    For the data request, back up a moment and think about it like this: what would you do if instead of an AJAX request, this was a SOAP web service request? Would you still send the request through Fusebox? Why not? Surely you could use Fusebox to build up the SOAP response data and header. As you say, it "seems nice and clean as there is one way for getting access to data".

    OK, I'm sure after a moment of thought you would agree this is a terrible idea. ColdFusion already will generate web service responses for you. But you must let the request hit a CFC in order to do this.

    Now ask yourself how you would secure this. If you have all of your security logic in Fusebox, you are going to have a hard time implementing security for your web service. What does this reveal? That the Controller is not a very good place to handle all of the security. Where you really want to wrap up the security logic is, again, in a CFC in your model. You might CALL this SecurityService CFC from your controller (in fact you almost certainly would) but the security logic itself would not be in the controller.

    Ahh, and if you have a SecurityService CFC, now it is possible to use the same service to secure your web service requests. Without having to try to force the request through Fusebox.

    Now back up even further. What if you want to allow Flash Remoting requests to your model from a Flex application. Now you have no choice, Fusebox cannot generate the binary AMF format no matter what you try to do. You must use a CFC. Which means by this point if you can't secure the remote method calls without having to go through Fusebox, you're out of luck.

    Hopefully this is revealing the big difference between data reqeusts and content requests, as well as why you would want to refactor your system to allow for direct access to your model via CFCs. Basically, the questions to ask yourself are: How hard would it be for me to allow Flash Remoting, web services to request data? How hard would it be for me to switch frameworks from Fusebox to Mach-II? How easy is it for me to test my model, including security? The answer to all of these questions should ideally be "very easy". I think you'd agree that right now, from what you've said, then answer for you would be "very hard". Which means that you've got some thinking to do about refactoring your system as time goes on. Hopefully that helps?

  • # Posted By sal | 7/27/07 2:43 PM

    Would this essentially be what Joe Rinehart calls structred (data requests) and unstructred (content requests) ajax? Interesting read Brian.

    cheers

  • # Posted By Simon | 7/31/07 4:27 AM

    HI Brain,

    Thanks for taking to the time to clearly show me where I'm would be going wrong if i was to try putting all requests though FB. You lengthly post was extremely helpful. Thanks for the time you spent.

    Simon

  • # Posted By Scott Terrell | 8/21/07 9:43 AM

    In using the basic example, I get the error "exception thrown and not caught". The cfc I can hit directly through a url (e.g., art.cfc?method=getmedia) and it returns the appropriate data set.

    When I try to bind it, I get the error. Any help would be appreciated.

    <cfform>
    <table>
    <tr>
    <td>Select Media Type:</td>
    <td><cfselect name="mediaid"
    bind="url:art.cfc?method=getmedia"
    value="CountryID"
    display="CountryName"
    bindonload="true" method="remote" /></td>
    </tr>
    </table>
    </cfform>

    cfc:

    <cfcomponent output="no">
       <cfset THIS.dsn="axdealer">
       
       <!--- Get array of media types --->
    <cffunction name="getMedia" access="remote" returnType="query" >
    <!--- Define variables --->
    <cfset var data="">

    <!--- Get data --->
    <cfquery name="data" datasource="#THIS.dsn#">
    SELECT Country_ID as CountryID, Country_Name as CountryName
    FROM Countries
    ORDER BY Country_Name
    </cfquery>

    <!--- And return it --->
    <cfreturn data>
    </cffunction>

    </cfcomponent>

  • # Posted By Brian Kotek | 8/21/07 9:48 AM

    Try using CFC binding instead of URL binding. When you call a CFC via the URL, the results come back as WDDX which will not properly feed an AJAX form control.

  • # Posted By Paul | 9/19/07 3:32 PM

    I am new to Ajax and am trying to get a handle on how it will work with the MVC framework in Fusebox5.

    At the moment I have a controller circuit where a fuseaction will call the model and view circuits to construct the whole page out of content variables. If I wished to replace a traditional link with an ajax link how would this affet my overall design. Would I keep my circuits and <cfincludes> in the same place in Model Controller and View directories but populate my layout cfm page with cfdivs which call the original exit fusactions?

  • # Posted By Jim | 10/11/07 9:32 AM

    I recently installed CF8 and cannot get the bind:cfc with cfform objects to work. The cfc works with cfinvoke. If is turn on the cfdebug option the debug window shows the correct data coming back from the cfc but it is never loaded into the form object. No errors are displayed. I tested this is IE6 & 7 and FF 2.0 (with firebug) and get the same negative results. I'm running IIS6 on a win2003 server and there is a virtrul folder for CFIDE.
    Does anyone have clue to what could be wrong? thanks - Jim

  • # Posted By Brian | 10/11/07 9:41 AM

    Not sure Jim, since I've been using binding with no problems. My advice would be to look at the sample apps, and check out Ben Forta's site where he has several examples (in fact if you Google around you'll find tons of CF8 AJAX examples at various blogs). Get those running to prove to yourself that it works, then compare it to your code to see if you can find your error.

  • # Posted By Paul Hopkinson | 10/18/07 10:42 AM

    Jijm I suspect your getting the same error as we are - 'Exception thrown and not caught'.

    I've found that taking the cfform & cfc templates out and running them by themselves independatly of any other tempaltes (ie application.cfm, fusebox framework etc) then it works - but put them back into a framework of any kind and it blows up

    Does anyone have the solution to this as it's driving me nuts

    Cheers

    Paul

  • # Posted By Brian | 10/18/07 12:30 PM

    You might have a look at my Framework-Agnostic Models presentation (in the sidebar). I have a version using Fusebox and the CF8 AJAX functions and it works fine. So the bottom line is the AJAX stuff works fine with a framework. You have to be doing something incorrectly somewhere.

  • # Posted By Jim | 10/18/07 1:18 PM

    I still can't get the ajax bind to work in my IIS/CF setup. I did install CF8 devleoper version on a separate pc using the built in webserver that comes with the install and the exact code worked.

    I don't get any errors when I run the code. I've tried it in IE 6/7 with cfdebug on and it shows the data coming back from the cfc, but it doesn't bind with the cfinput object inside cfform. I also tried it in FF2.0 with firebug running and got the same negative results with no errors.

    My next attempt will be to replace the IIS server with Apache.

    If anyone out there has the bind working on a IIS/CF8 setup I'd like to know how you did it.

    Thanks, Jim

  • # Posted By Paul Hopkinson | 10/19/07 3:18 AM

    hmmm - it is exactly the same code in both places.

    I shall continue to hunt it out!

  • # Posted By Will | 10/29/07 5:35 PM

    hi, i'm having the exact same problem as Jim, is there any info on how to fix this, or even why this is happening?

  • # Posted By Mykola | 11/14/07 4:17 PM

    Make sure the path to CFC does not rely on IIS virtual folder or CF mapping. It only should be a relative to Web Root path.