Version 11.1 by smmccraw on 2007/07/08 09:43

Hide last authors
Quinton Dolan 4.1 1 === Pierce T. Wetter III ===
2
3 ==== Myth: Rails is a better framework for Ajax than WO. ====
4
5 Reality: WebObjects is actually a better framework for use with Ajax libraries than Rails because it has a better component system than Rails. You spend a lot of time coding little tiny XML and HTML generators when doing Ajax and WO's component system makes that very DRY (Don't Repeat Yourself).
6
7 ==== Myth: WebObjects is hard to use with Ajax. ====
8
9 Reality: WebObjects is easy to use with Ajax, it's just that there is only one known library for Ajax-WO support, and its not well documented. Even then the library only goes so far in that it just provides new components to wrap a few script.aculo.us tags. I think its more of a documentation gap, not a code gap.
10
11 Additionally, the WO documentation has always pushed people erroneously towards component actions and away from direct actions. If you use 90% direct actions like I do in my application, (See my "WebObjects on Rails" post), you'll find that direct actions are simple to code in reality, and very much like Rails which basically doesn't have component actions at all.
12
smmccraw 10.1 13 //[[Which is to say, if you avoid much of the power of WO, and don't use component actions, ajax will be easier. If you do use component actions - and I have yet to work on a project that doesn't - then ajax use seems like it will blow your page cache, as described below. So it really is easy to use AJAX in WO. Really easy. It's just that it doesn't work]]//
Quinton Dolan 4.1 14
15 //[[mschrag: While I agree with the above commenter that component actions provide a huge amount of power in WO, it is NOT true that Ajax and component actions are incompatible. ~[Project Wonder's Ajax components>>Programming__WebObjects-Project_WONDER-Frameworks-Ajax]] directly addresses the use of component actions with Ajax in a way that does NOT blow the page cache. While it is true that the implementation of these capabilities inside of Wonder was non-trivial, it demonstrates that it is, in fact, possible, and if you use the PW components along with ERXSession, you will get this capability for free.]//
16
17 ==== Myth: You can't assign the name or id value of tags in WebObjects. ====
18
19 I'm mentioning this one explicitly, because I had someone ask me about this recently, because they were trying to assign a WYSIWYG JavaScript editor to a text area.
20
21 Reality: Actually, what really happens is that if you DON'T have a name=value or id=value line for your TextArea in WebObjects, it will generate a unique one for you. But you're more than welcome to specify one in your .wod file, and WO will use that. It's then up to //you// to make sure its unique, so that you don't have multiple text area tags with the same name. In other words if you only have one textarea you wish to attach a Javascript WYSIWYG editor to, just add:
22
smmccraw 10.1 23 {{panel}}
Quinton Dolan 4.1 24
Marc Guenther 8.1 25 textarea: WOText
26 {
27 id='wysiwyg';
28 name='wysiwyg';
29 value=textValue;
30 }
Quinton Dolan 4.1 31
smmccraw 10.1 32 {{/panel}}
Quinton Dolan 4.1 33
34 in your .wod file and you can use id with your Javascript just fine.
35
36 ==== Myth: WebObjects generates HTML ====
37
38 Reality: Just because the components of your .wo file are .html and .wod doesn't mean WebObjects can only generate HTML. WebObjects is really at heart, a very, very, very, complicated printf. The result of a component can be HTML, XML, JavaScript, or even binary data. You can actually put whatever you want in the .HTML and treat WebObjects like a giant merge engine. For instance, you could generate PDF files using WebObjects; they're just text, and you could substitute text into the middle of the PDF boilerplate pretty easily.
39
40 ==== Background ====
41
42 We haven't used a lot of JavaScript at www.marketocracy.com, for a very simple reason: We don't have the testing staff to fire up 10 different browser variations to test the site. And lets face it, programming in JavaScript sucks.
43
Marc Guenther 8.1 44 Since someone invented that cool acronym though, that's changing. You would think it shouldn't matter that something has a name, but it does. I remember when the GoF Design Patterns book came out. There was nothing in there I hadn't figured out on my own, but now they had a name!//I//could//say//"Singleton"//to//my//co-workers//and//they//would//know//what//I//was//talking//about.//I//could//buy//a//junior//engineer//the//book,//and//he//would//soon//be//programming//at//a//much//higher//level.//
Quinton Dolan 4.1 45
Marc Guenther 8.1 46 So//having//a//name//helped,//and//the//result//is//that//there//are//a//lot//of//cool//toolkits//out//there.//Since//someone//else//wrote//the//JavaScript,//that//means//I//don't//need//to//test//10//different//browser//variations.//
Quinton Dolan 4.1 47
Marc Guenther 8.1 48 Which//means//I//can//make//the//site//much//easier//to//use//and//more//interactive.//Huzzah!
49
Quinton Dolan 4.1 50 ==== Research ====
51
52 So the first thing I did was that I'd heard that Rails was cool and made Ajax easy. I'd heard that before, but that was when the version number was 0.13... So I went out and bought the Rails books and you know what I found?
53
54 It's not that Rails rocks with Ajax, its that the Prototype Javascript library rocks. The documentation makes a big deal about doing Ajax with one line of code.
55
smmccraw 10.1 56 {{panel}}
Quinton Dolan 4.1 57
Marc Guenther 8.1 58 <div id='<= posting.id'>
59 <%= link_to_remote [div to update] [link options] -> %>
60 </div>
Quinton Dolan 4.1 61
smmccraw 10.1 62 {{/panel}}
Quinton Dolan 4.1 63
64 The reality is that all Rails is doing is writing one line of JavaScript. From the Ajaxy "rating" code I've been adding to my app, look at the following:
65
smmccraw 10.1 66 {{panel}}
Quinton Dolan 4.1 67
Marc Guenther 8.1 68 <div id='<WEBOBJECT name=postingID></WEBBOBJECT>'>
smmccraw 10.1 69 <a href="#" onclick="new Ajax.Updater('<WEBOBJECT name=postingID></WEBBOBJECT>', '<WEBOBJECT name=ratePosting></WEBOBJECT>', {asynchronous:true, evalScripts:true}); return false;">1</a>
Marc Guenther 8.1 70 </div>
Quinton Dolan 4.1 71
smmccraw 10.1 72 {{/panel}}
Quinton Dolan 4.1 73
74 Ok, so lets break it down. The way Ajax.Updater works from the Prototype library is you give it the id of a DOM object and a URL, and it replaces the DOM object with that id with the contents of the URL. Usually, you specify the area to update with a div tag which I've shown for completeness. For ratings I would need 1 div tag to enclose all 5 rating stars: <div><a></a><a></a><a></a><a></a><a></a></div>. I would also use a WOGenericContainer to generate the div tag with the right id rather than using the id='<WEBOBJECT name=postingID></WEBBOBJECT>' line, but I wanted it to be obvious it was div tag.
75
76 So the Ajaxy part is the <a> tag, not the div tag.
77
78 Here I have a manually built <a> tag with an onclick bit of javascript. That makes a single call out to the Prototype library, which has this cool call:
79
smmccraw 10.1 80 {{panel}}
Quinton Dolan 4.1 81
Marc Guenther 8.1 82 new Ajax.Updater( elementid, url, options)
Quinton Dolan 4.1 83
smmccraw 10.1 84 {{/panel}}
Quinton Dolan 4.1 85
86 It does something very simple: It pulls the HTML from the specified URL, and replaces the element with the specified id with the downloaded HTML.
87
88 The two WebObjects tags specify the element ID and the link, they're just a WOString and a WOActionURL:
89
smmccraw 10.1 90 {{panel}}
Quinton Dolan 4.1 91
Marc Guenther 8.1 92 postingID: WOString { currentPosting.primaryKeyString; }
93 ratePosting: WOActionURL { see discussion }
Quinton Dolan 4.1 94
smmccraw 10.1 95 {{/panel}}
Quinton Dolan 4.1 96
97 Now in my case, I'm a direct action snob. So my WOActionURL would look like the following:
98
smmccraw 10.1 99 {{panel}}
Quinton Dolan 4.1 100
Marc Guenther 8.1 101 ratePosting :WOActionURL
102 {
103 directActionName="PostingRater";
104 ?pkey=currentPosting.primaryKey;
105 ?rating=cRating;
106 ?wosid=NO;
107 }
Quinton Dolan 4.1 108
smmccraw 10.1 109 {{/panel}}
Quinton Dolan 4.1 110
111 This produces a result similar to Rails, because in rails you have to define an action for each class of link. In my case I tie directactions to pages/components, so my "PostingRater" page would return component-level HTML (minus any HEAD/BODY tags) that matched the existing <div> definition. Since we're using WebObjects, that turns out to be trivially easy if we build the enclosing <div> tag with a component PostingRater can just look like:
112
smmccraw 10.1 113 {{panel}}
Quinton Dolan 4.1 114
Marc Guenther 8.1 115 <WEBOBJECT name=RatingDiv></WEBOBJECT>
Quinton Dolan 4.1 116
smmccraw 10.1 117 {{/panel}}
Quinton Dolan 4.1 118
119 Using component actions, it could be even simpler:
120
smmccraw 10.1 121 {{panel}}
Quinton Dolan 4.1 122
Marc Guenther 8.1 123 ratePosting: WOActionURL { action=ratePosting;}
Quinton Dolan 4.1 124
smmccraw 10.1 125 {{/panel}}
Quinton Dolan 4.1 126
127 Because WebObjects, unlike Rails can have stateful components, the RatingDiv component could actually have all the logic and return self as the result of the action:
128
smmccraw 10.1 129 {{panel}}
Quinton Dolan 4.1 130
Marc Guenther 8.1 131 public WOReponse ratePosting
132 {
133 currentPosting.ratePosting(currentRating);
134 return self; // since this is called from JavaScript
135 // return just myself, not self.page
136 // this will tell WO to render only
137 // this as a result.
138 }
Quinton Dolan 4.1 139
smmccraw 10.1 140 {{/panel}}
Quinton Dolan 4.1 141
142 That is, the link for the javascript would go into the RatingDiv component with everything already setup: the current posting, the current rating. Returning self then causes the div to regenerate.
143
144 **However, there's a gotcha there, because component actions called from javascript count towards your backtracking count. Since someone might be going down through the page clicking rating after rating, that could be a problem. If your max backtracking count was 10, and you had 20 postings on a page, they wouldn't be able to rate the 11th page.**
145
146 So where Rails has one line, I have two WOTags, but those could (and should) be easily combined by creating a WODynamicElement to generate the link directly. In essence, it would be pretty easy to create a "RemoteLink" WODynamicElement that did everything the Rails "link//to//remote" call did, namely take an id to update along with all the options WOActionURL takes.
147
148 But additionally the WebObjects solution is superior in a number of ways to the Rails solution. Rails has support for both "partial pages" and "components" but the reality is that components are pretty heavyweight/slow and partials don't quite do what you think. So the WebObjects solution, by wrapping both the logic and state into a component ends up being more DRY (Don't Repeat Yourself) and better encapsulated than the typical Rails solution. In the page where you want the Ajax bit, you specify the component, and you put the ajax handling logic in the component itself.
149
150 I have yet to see anything in the Rails Ajax support that couldn't be just as easily done in WO via a combination of WOComponents and WODynamicElements. Pretty much everything in the Rail "Ajax support" are one-liners in Prototype. In fact, because pages/components can have state, its probably //easier// to do it in WO than in other systems. Also, I think you could build a set of WOComponents that provided //superior// Ajax support than Rails. It's just that no one has written the supporting WODynamicElements or WOComponents.
151
152 Now looking at the dojo Hello World example Ahmet, I have to say, that there's nothing in WebObjects that precludes doing anything in this. 90% of this tutorial is JavaScript that isn't specific to any particular technology. The parts that are specific to PHP/ASP/ColdFusion are defining a new page just like you'd have to do in WebObjects. Just use a WOActionURL where it says url: in the Javascript and you're done.
153
154 I also think, that from this example, dojo is a bit weak as a Javascript toolkit. You'll spend a lot of time wiring stuff up in Javascript with Dojo compared to Prototype. Or contrast dojo with the Yahoo UI library:
155
156 http:~/~/developer.yahoo.com/yui/
157
158 The whole "Dialog" thing in yui is cool:
159
160 http:~/~/developer.yahoo.com/yui/container/dialog/index.html
161
162 And would lend itself quite readily to the model WO has of building pages out of pieces.
163
164 Then again, dojo is only at version 0.3. The WYSIWYG editor is nice, but I really don't want to have to define my dialog boxes in yet another tag language. HTML is good enough for me.
165
166 So exactly what problems are you having with dojo/wo? Consider that the problem may be dojo, not WO in particular. You could easily create a WODynamicElement for every new dojo tag, collect them in components, and have something much easier to use than straight dojo.
167
168 Category:WebObjects