Raymond Camden's Blog Rss

I heart Spry

44

Posted in | Posted on 06-02-2006 | 17,972 views

I'm a bit late to the party, but I finally took some time to check out the Spry framework, Adobe's answer to the AJAX craze. I haven't been that impressed with AJAX. I mean, it's useful, yes. Very useful. But it's also kind of old and so it isn't really new to me. I've been thinking about learning a bit of AJAX for use in the back end of BlogCFC. I took some time early this morning to look at Spry.

Wow.

I mean, seriously, Adobe, could you make this a bit simpler? I think it was harder to put my shoes on this morning. Consider the following simple example (and this is not 100% complete, but it gives you an idea of how short the code is):

view plain print about
1<script type="text/javascript" src="includes/xpath.js"></script>
2<script type="text/javascript" src="includes/SpryData.js"></script>
3<!-- load the xml, notice the xpath support -->
4<script type="text/javascript">
5var dsHatches = new Spry.Data.XMLDataSet("dharma.xml", "hatches/hatch");
6</script>
7
8<!-- now bind it to an html table -->
9<div id="Hatches_DIV" spryregion="dsHatches">
10<!--Display the data in a table-->
11<table>
12<tr>
13<th>Hatch</th>
14<th>Icon</th>
15<th>Active</th>
16</tr>
17<tr spryrepeat="dsHatches">
18<td>{hatch}</td>
19<td><img src="/images/dharma/{icon}"></td>
20<td>{active}</td>
21</tr>
22</table>
23</div>

So the first line loads the data set from XML. It uses XPath to translate this into a data set. I can then bind it to a table by using the spryregion and spryrepeat tags. Notice the use of bound variables inside.

For a more complete demo, check out the Spry front end version of BlogCFC. Make sure you view source on that.

I did run into one interesting problem. I knew that I needed XML, so I knew I couldn't just use my blog's main CFC. I wrote a new CFC that would handle the few methods I needed and return them as XML. (This was rather boring, but I did make two cool little functions you may like, arrayToXML and queryToXML. Both of these already exist on CFLib I think, but I wrote my own for the heck of it.)

I thought that was all I needed, but it wasn't loading. Then I tried making the same request Spry was, and I found out what it was. ColdFusion was wrapping my response in WDDX. So what could I do? (I wish CFC's had an option to NOT wrap the result in WDDX and just return it "bare".) I wrote another file, this time a CFM. It simply acted as a proxy to call my other proxy CFC. It then returned the XML correctly.

I think I spent more time in ColdFusion then I did in JavaScript. That to me is a good thing. It means Adobe really did a darn good job with this framework. This is exactly the kind of thing I can see using in real world applications.

I definitely recommend my readers to take a few minutes and download the framework. I think you will find it worth your while.

Comments

[Add Comment] [Subscribe to Comments]

After posting on the CF list I found these little gems and thought others might like to have look.

Thanks to Massimo (http://www.massimocorner.com):
http://www.olimpo.ch/tmt/tag/spryxml/
http://www.olimpo.ch/tmt/tag/sprydataset/
Cool stuff. I was planning on sharing my utils as well. So hopefully he won't mind. :) I'm thinking of a generic proxy CFM that will be written in ways like a CFC. But you could do stuff like:

/foo.cfc?cfc=path.to.cfc&method=X&arg1=val1

Etc.
It doesn't look like your example has any dynamic updating. If that's the case, than this example is the same as looping over query data into a table with a CF server side script...right? (not that there's anything wrong with that)

I'll need to spend time with their dynamic master/detail feature before I get too excited.

Looking over their documentation, there's probably a way to create a CF custom tag that accepts a query, and two sets of column names (master cols and detail cols) and automatically generates a dynamic master/detail page similar to their examples. Now THAT would be nice. ;-)

Thanks for bringing this topic up again. I have been meaning to spend more time looking over SPRY.
Yes, I should have made it clear this was a read only demo.
Thanks for the demo. I had looked at the adobe labs page recently, but it was nice to see an implementation. I'm definitely going to be using spry now and your xml cfcs!
Something I would like to add, is that you cannot use this framework (yet) as purely an AJAX solution. I am working on a project right now that is using AJAX technology and I attempted to use the Spry framework for this. The problem I had is that, I didn't need the Ajax transaction when loading thet page nor did I have any datasets to return. I wanted to submit a transaction when the user submitted a form. What happened is that Spry threw an error because it did not receive any data wehn the page loaded. You cannot specifically tell it to wait for the data, it wants it to be available upon loading the page. I suppose a workaround could have been sending blank data, but I just decided to switch to Prototype. I do however, like how Spry acts in a very similar way to the Cfoutput-query function. Very slick.
Kyle, I don't remember anything saying that stuff had to be loaded immidiately. I think that's just how their demos work in general. I'll post to the forums and see if I can confirm that.
I just created this page as an example:
http://www.kylehayes.info/sendFeed/spryeg.cfm

As you can see, because I don't call the dataset initially, I get an error. And the only way to prevent this error is to create a dataset, that simply has no data in it (at least from what I have found).
I suppose what I could do is create this kind of dataset:

var dsStatus = new Spry.Data.XMLDataSet("", "status/message");

where I am not passing a url but I am passing the arguments that desribe how the data will be coming in.
>ColdFusion was wrapping my response in WDDX. So what could I do?

Ray, I found this problem myself in CF7 when I was playing around with ajax. So in CF7.1 I modified the return behavior of CFCs. As you discovered, by default if you request a CFC from a URL all values are wrapped in WDDX (this way you can return complex types). However, now there is one exception. If you set the ReturnType="XML" we won't wrap it in wddx.
7.1.... that's the latest released version, or is that Mystic? (Either way - Mike - this is cool to here. Thank you!)
Kyle - now be clear on this - I'm new to Spry so I could be wrong, so plese take what I say with a grain of salt. The reason you get an error is because you are trying to use the binding and the data is not there. Therefore, the error makes sense. If you don't want data to load immediately, you can't use the fancy binding. But - you can still use the AJAX features along with the xpath parsing. You would just need to build the result yourself. So, you can use Spry to call the XML resource and than take the nice dataset result and do with it what you want. Add to a drop down, modify text fields, whatever. I'd still consider this pretty darn useful.
Well, guess what I found wrong with the demo. Bet you did a CSS layout! LOL, if the window is to small it doesn't display content in the right place.
Ray - Thank you for that insight. I think what you said is probably right. The day I tried the Spry framework, I did not delve into the documentation details of the various functions and objects, so I didn't even think abou the fact that the object returned is probably still an xml dataset. Thank you for looking into this, Ray. I really did want to like Spry (as I have been an Adobe guy for so many years). So I shall give it another chance. Onward, Mission: I heart Spry!
My only real rub with the framework is that it required proprietary extensions to the HTML syntax, which means that it's going to break validators. Personally, I don't really care if it doesn't validate on account of these extensions, but it's something to consider that you're now augmenting the standard HTML syntax with proprietary code. Wasn't Microsoft lambasted for trying to do the same thing several years ago?
Has anyone got this to work using a dataset returned from a CFC? If I run the CFC method on its own I get the XML document returned to the browser, but calling the same URL in the javascript function fails.
CFCs return their data WDDX encoded. Did you ry using returnType="xml" as Nimer described above?
I had the returntype set to XML. I have some other things to work on but hopefully I'll get a chance to look into this again. Spry looks like a great start from Adobe.
Ray, yes, Mike meant CF 7.0.1.

HTH
Damon
Thanks. I tested on Mystic but am glad to hear it's in the released edition as well.
I really wanted to check out this demo after hearing about it on the Helms & Peters Podcast, but I get a CF file not found error on the demo link (/spry/blog.cfm).
Fixed Dave.
I am trying to sort this all out in my head from square 1. So how does the data come from the CFC? Can you talk more about that aspect, OR is there a resouce that I have missed somewhere along the way that explains that.

Thanks.
CFCs can return data to remote clients - not just to local CF code. So I can point Spry to a CFC method that returns XML. In THIS blog entry I said I couldn't, and I had to point to a CFM, but Mike Nimer let me know that I could point to a CFC if the returnType was XML (if you don't do that, then the CFC wraps the result in WDDX).
Great. I used the tag from one of the links above which itegrated quite nicely.

New question regarding formatting of content. How? it looks like the typical html tags are not interpreted. Are there any work arounds for this?

Thanks!
I'm not quite sure I get what you mean. Spry lets you formdata anyway you want. So for example: &lt;b&gt;{foo}&lt;/&gt;. I surrounded the foo token with bold tags. I can really use any layout I would like.
formdata=format data
Sorry. Here is an example.

http://www.tusker.com/Spry_P1_3_08-11/samples/Zugg...

Currently there is some additional garbage because it was pasted directly from word but it shows what I'm am referrering to. All of the HTML tags are treated as text.
Oh you mean the HTML returned from XML. Yes, there is a solution to that. Give me a few to dig it up from my brain.
Ok, you have to do this server side where the XML is generated. It needs to wrap the info in cdata. Here is an example from my blog demo:

<cfset txt = "<![CDATA[" & txt & "]]" & ">">

I basically use this to wrap text that may have html. For text that won't have html, I don't wrap it like that. I do this instead:

<cfset txt = xmlFormat(txt)>

I can't take credit for this - I believe Adobe posted a response to me on the forums.
In the spryxlm.cfm tag the formatting is structured as:

<cfset fieldsList = LCase(attributes.variable.columnList)>
<cfset xmlData = "">
<cfloop query="attributes.variable">
   <cfset jsRow = "">
      <cfloop index="x" list="#fieldsList#">
      <cfset jsRow = jsRow & "<" & x & ">" & XMLFormat(attributes.variable[x][attributes.variable.currentRow]) & "</" & x & ">">
   </cfloop>
   <cfset xmlData = xmlData & "<#attributes.rownode#>" & jsRow & "</#attributes.rownode#>" & Chr(13)& Chr(10)>
</cfloop>

I saw your other posting where you implemented the CDATA but as the structure of this is slightly different, I am unsure how to include it. I tried replacing the XMLFormat but it puked.

<cfset jsRow = jsRow & "<" & x & ">" & XMLFormat(attributes.variable[x][attributes.variable.currentRow]) & "</" & x & ">">
Heh, ok, but _how_ did it puke? :) Remember for the lines you cdata you DONT use xmlFormat on the value.
Is that what you used <cfif listFindNoCase(arguments.cDataCols, col)> for? Does encapsulating everything cause the errror?

<cfset fieldsList = LCase(attributes.variable.columnList)>
<cfset xmlData = "">
<cfloop query="attributes.variable">
   <cfset jsRow = "">
      <cfloop index="x" list="#fieldsList#">
      <cfset jsRow = jsRow & "<" & x & ">" & <![CDATA[" & attributes.variable[x][attributes.variable.currentRow] & "]]></" & x & ">">
   </cfloop>
   <cfset xmlData = xmlData & "<#attributes.rownode#>" & jsRow & "</#attributes.rownode#>" & Chr(13)& Chr(10)>
</cfloop>
Got it! Thanks for your help. Obviously some syntax issue. This works

<cfset jsRow = jsRow & "<" & x & "><![CDATA[" & attributes.variable[x][attributes.variable.currentRow] & "]]></" & x & ">">
Cold Fusion is dead

http://www.tiobe.com/index.htm?tiobe_index

grow up.
God: I refuse to listen to anyone who doesn't post a real name. If you are convinced that CF is dead, have the guts to stand up and at least be honest about who you are. The TIOBE index is not perfect and does not cover a lot of places where CF rules - intranets. Anyway, this comment is not even on topic.
Yeah, Ray, you tell 'em!
Ray, I personally know God. He loves me so much he gave his son for me. Yet, on the subject of ColdFusion my opinion is this imposter will be dead before ColdFusion is!
Hi Ray.

I've finally sat down with Spry this morning and have been working it, testing this, trying that etc. So far, so good. I really like that I'm seeing and I can see how incredibly useful this is.

One question:

What's a nice way (or good way) to create something like a nested/grouped output?

I've got a dataset that contains item names, they constitute 'groups' of data. Each item in turn has a number of locations and finally details.

So if I want to output and group by item name, then location then display the details what's your observation on best route with Spry?
I just got Dreamweaver CS3 yesterday and WOW!!! it makes using Spry so easy. I know Dreamweaver isn't the favorite coding product out there, but I now see how all this Spry stuff works into Adobe's master plan. :-)

If there's an annoyance, it's that the Spry version of the dynamic table doesn't have paging built in.
@Bryan: I'd use 2 datasets. Remember that the URL of a dataset can be bound to a value from another dataset. Search my blog for the CFLib Spry demo as it shows an example of this.

@Dan: I've heard this. I downloaded the demo just to see it - but I haven't tried it yet.

Spry does support paging - it may not be in an easy DWMX wizard though.
Re paging: The Spry documentation (http://livedocs.adobe.com/en_US/Spry/1.4/index.htm...) isn't very clear on how to use the dynamic table. (Livedocs aren't easy to search) Your blog is a great help, but where do you go to get your info on Spry?
To answer my own question, most of your blog posts still refer to Adobe Labs for Spry documentation. I wonder why the official released livedocs help (referred to by Dreamweaver) doesn't include the entirety of that labs info...

Hmmm. Obviously this is rhetorical. ...now back to your regularly scheduled programming. ;-)
I think paging may not be officially "baked" in yet, if that makes sense. I mean the whole framework is still in development of course, but I believe paging may not be "officially unofficial" yet. ;)

Does that make sense? Thank you for the link though - I'm going to blog it a bit later.

[Add Comment] [Subscribe to Comments]