In WebObjects, Components take the role of a view controller in what passes for Cocoa’s version of MVC. Each is responsible for calculating the data that the view objects are bound to: you saw an example of this in the previous post. Each is also responsible for responding to user interface events—called actions—and preparing the next component where that’s required.
Navigating between components
Let’s add a new component to our HelloGSW test app. We’ve recorded the date that the visitor arrived at the site, we could (for sake of demonstration, not because it’s useful) find out how long it takes that visitor to get to the next page. We’ll come onto the mechanics of adding it to the project later, but for now we note that we require a way for the visitor to indicate their intention to see the next page. That means, as a simple way to do things, having a form with a submit button.
We could write the form into the HTML, but then we’d have to know what URL the WO machinery was going to use to call our action. So we’ll use WebObjects to generate the form, using this HTML:
<webobject name=form> <webobject name=submit_button><INPUT TYPE="SUBMIT"></webobject> </webobject>
As you’ve seen, the data bindings for each webobject need to be defined in the WOD file:
form:WOForm {} submit_button:WOSubmitButton {action = nextPage}
As with the value binding you saw last time, we can bind the action of the submit button to a method on the component. Those of you who have used Cocoa Bindings may be surprised to find that you can do the same with NSResponder subclasses, though it’s rare to see it done with Mac apps.
So finally, I GIVE YOU TEH CODEZ:
- (GSWComponent *)nextPage { ClickDelay *nextComponent = (ClickDelay *)[self pageWithName: @"ClickDelay"]; nextComponent.startDate = accessedAt; return nextComponent; }
As with view controllers on the iPhone, you just create the new component (-pageWithName: does that, and configures its context correctly) and configure state where appropriate. Unlike with iOS view controllers, you don’t specify how they get presented because there’s only one way that will (probably) ever happen: in an HTTP response. So you can just return the next component from the method and the Right Thing™ will happen. If you return nil, the visitor will see the current component again (though with a whole server round-trip and a fresh HTML response, so it’s best to do some AJAXey thing: on which more later!).
If you’re really interested in how the other component works, check out its source from GitHub.
But that’s not why we’re here.
Adding a component involves a boatload of boilerplate: five new files, and a change to the GNUmakefile. That’s one more boatload than you’d like to write every time you create a new page in your web app, yes?
Yes. Therefore what I actually did was to write a script to do all of that boilerplate for me. It’s really basic (error checking is for security boffins. Oh, wait.) but will do the necessary dance. Just be sure not to run it twice for the same component yet…
What I really need is a tool that’s both more robust, and that can generate the other things you need in writing a WO app. I’ll start right now, but pull requests are always welcome…