Composeable Views in Seaside

So I was talking to a Ruby on Rails buddy of mine today, and he asked me if Seaside could do views composed from other views like Rails. I thought I'd throw up a quick sample in case any one else wonders how this is done. It's a very common thing to do, so common, I'd never considered writing about it until today.

It's very basic, contains a header, footer, main control, and a result control to show how lists of items can each be their own views. MVC is so ordinary in Seaside I forget how novel it is to some other frameworks.

I start off creating a simple header control with one method...

Header>>renderContentOn: html
    html div: 'Header'

Then a footer control doing the same, though each could be much more complex...

Footer>>renderContentOn: html
    html div: 'Footer'

Ok, now I'll create a class for showing the results of a query, with each result being a component of its own...

ClassResult>>modelClass: aModel 
    modelClass := aModel

ClassResult>renderContentOn: html 
    html heading: modelClass name level: 3.
    html div: ((modelClass allSubclasses 
        collect: [:each | each name]) join: ', ')

I just printed the class name, and under it, all its subclasses names separated by a comma.

Now for the main root component that will be composed of these subcomponents...

ClassUsage class>>canBeRoot

    "setup sub components in instance variables, for the results, 
    I'm grabbing all the subclasses of WAComponent that have subclasses 
    themselves and then sorting them by how many subclasses they have, 
    and then using them as the model in a view, and storing the list of 
    views for later rendering."

    super initialize.
    header := Header new.
    footer := Footer new.
    results := ((WAComponent allSubclasses 
                reject: [:each | each allSubclasses isEmpty]) 
                    asSortedCollection: [:a :b | 
                        a allSubclasses size > b allSubclasses size]) 
                    collect: [:each | ClassResult new modelClass: each]

    "return all sub components as a list"

    ^{ header. footer } , results asOrderedCollection

ClassUsage>>renderContentOn: html 
    html render: header.
    (html div)
        class: #body;
        with: [results do: [:each | html render: each]].
    html render: footer

That's about it. I setup the subcomponents in the initialize, and then by explicitly not calling super renderContentOn, I then have the option of when and where to render subcomponents.

Comments (automatically disabled after 1 year)

Giles Bowkett 6372 days ago

Partials in Rails are its big weakness next to Seaside. I was working to convince some people that Seaside is awesome and my big winning argument was "render :partial == GOTO."

Ramon Leon 6371 days ago

I'm not actually that familiar with Rails, beyond discussing it with Rails developers, nor do I have any intentions of learning it deeply, I already know Seaside and couldn't be happier with a framework. Rails is still dealing with request/response and doing things the old fashioned way.

about me|good books|popular posts|atom|rss