Hello, in this sequence, you'll see the power of Seaside,
through the composition of components.
We defined the reusable and stateful components,
now we'll see how we can put these components together
in order to build complex applications. As we said, an application
is a root component,
so we benefit from debugging, of live debugging of applications.
We'll go back over 3 important mechanisms
for composing components in Seaside.
The first is component aggregation.
Remember, we defined 2 counters,
one normal counter, which looked like this
and a Twitter counter, here.
OK?
How can I now aggregate a component counter
with a view to building a multi-counter application?
I want to show lots of counters on one page.
When I click on this +, for example,
it only increases the value of this particular counter, OK?
So, aggregating lots of components on the same page, easily.
So how do we do this in Seaside? It's extremely simple.
I'll define a component subclass, which is always the same,
which is called "WAMultiCounter",
"instance variable counters", defining a collection of counters.
In "method initialize" I'll create a collection of 5 counters, here.
OK?
And then I'll have the method "rendercontentOn", here
where I'll say I'll browse my counter collection with a "do"
and I'll ask each counter, at least, the html object,
to render each of the counters. I use a special method, "render".
This render method of the html object
allows you to ask a component to render itself, draw itself in html.
We've an important method here called "children",
which means that when a component encapsulates other components
and asks them to render in "renderContentOn",
it has to declare them, and to do that it has to render a collection
of components in its method "children"
which contains all the components it's going to render, all its children.
Here I'm rendering the collection "counters".
It's an important method to define.
So, the basic rules for aggregating components,
composing components is easy.
One component will store its subcomponents
in an instance variable. In our example it's "counters", OK?
It will then pass the "render" message
to html,
in its "renderContentOn" method, asking each child to render itself.
It will then redefine the method "children"
to declare all of its subcomponents.
There are always these 3 parts.
We can also aggregate different subcomponents.
They don't have to be the same type.
Before, I only combined counters and here we're going to have
an application, a MyApp component.
In the method "initialize" it's a collection,
except that in this collection I put
the app "Greeter" that we used in a previous sequence, which we saw,
a Tweeter counter and a counter. 3 components.
My method, "children" renders
all the children, the subcomponents of this MyApp component,
and in "renderContentOn"
I want to browse my children and ask them to render themselves.
So we do "html render: each"
and I'll do "html render" of Greeter,
the Twitter counter and counter.
Let's see what we get.
Here we have the Greeter component, which is displayed on the Web page,
we've the Twitter counter displayed here,
and the normal counter displayed here.
We've composed the components and they all work independently
if I click on the + and the "Say Hello" etc,
the components work perfectly.
So now, if you like, there's one stage further.
We don't want all the components at once on the Web page.
We want one at a time, a menu, for example, to select
which subcomponent we want displayed.
Typically, I only want to show the Greeter
and when I click on Twitter counter here,
I'm only going to display the Twitter counter.
How do we make this application? It's easy.
I add an instance variable in my MyApp application,
which is called the selected component, the selected child.
By default, I'll initialize it
to the first subcomponent,
In the "renderContentOn" method, here, I've modified it,
I'll display one menu,
giving me the possibility to select which subcomponent I display,
then I do "html render" but only of the subcomponent I want to display.
Quite simply.
In the menu, I'll generate one unordered list,
I'll browse all of my subcomponents
which I browse with an index, "i"
and I generate a list element for each child.
Here, I'm going to generate an anchor,
a clickable link, and when I click on this link,
it will trigger the callback, the execution of this block, here.
So we can say, it's easy, the component selected by the user
is the child number... so "self children".
Remember, it's a collection...
"at: i"
OK? And "i" here
is no more nor less than the number of the element
in the "children" collection.
So it's extremely easy to be able to browse all of the subcomponents
and to specifically generate, to completely control
what should and shouldn't be displayed.
We've a 2nd composition mechanism, which is "call answer".
We've seen components aggregation
with subcomponents, and now we'll see the "call answer" mechanism.
If we imagine, in the code of component A,
we'll write something that looks like this code here, we'll say,
component A calls component B. Call component B.
What will happen is, component B will mask component A on the Web page,
it will carry out a treatment,
and after a while, component B will say, "I've done my treatment,
"I'll do answer and give a result".
Here the result is a star,
and this result will be stored in X
in the place of "call component B".
Now, component B will reappear on the Web page
and component A can use this result to do something.
I'll show you an example.
Here we have a component, which was the counter.
We've added a button, here, "Set Value",
We imagine that "Set Value" allows the user
to enter a new value for the counter.
When we click on "Set Value" a new component is displayed,
which allows us to enter, a bit like the Greeter component,
we can enter a new value for the counter, click on "OK"
and when I click on "OK" it goes back to our counter component
but with the value entered here by the user at the beginning.
OK?
So we've a series of several components.
How is this implemented?
We've our Twitter counter with its "renderContentOn" method.
To its "renderContentOn" method we'll add a button,
a tbsButton, etc... This button's called "Set Value", here.
When we click on this button, this callback will be executed.
It's the "setCountToUserValue" method.
SetCountToUser is defined here.
What we do is we'll prepare a dialogue box here.
We'll use another component made by Seaside, a dialogue box.
which we'll configure here,
in this instance with "Enter a new value for the counter".
The default setting is 0 and we've an OK button.
What we'll do next...
The really interesting element is this line here...
Here...
We're going to say, "current component", so "Self".
Remember, "Self" is the Twitter counter.
"Call the dialogue box we've just created,
"and give me the result."
The result will be the new value of the counter.
Then, when we've finished here, we're going to say,
"count", so the value of the counter,
"Take this new value entered by the user in the form of a Number".
Quite simply.
So internally, we can examine the workings
of this WAInputDialog box.
It's a reusable Seaside component, totally classic,
except for one special feature,
it uses the "answer" method to send back a result.
If we look at the "renderContentOn" method
of this component,
when we click on its OK button,
here, it's the "submit" button,
it has a callback with a block, and in its callback
it will do "self answer: value".
Which means that this will send the result
to the component that called it.
It will really return to the place from which the call was made
and send the result.
We've seen the call/answer mechanism.
Now we'll see one last component composition mechanism,
the "Task" mechanism.
It's actually very simple.
Tasks are like components, but there are no UI parts,
so no "renderContentOn", no generation of htmls.
The idea is really to orchestrate,
to describe how the components should perform over time.
This component will do this first, then that one, etc...
Using "call: answer" behind the scenes.
So we'll define a task called an "Adder"
and then all the tasks have a method called "go".
Here, for example, in this task,
we'll ask the user to enter a number, so "self request: firstnumber"
then we'll ask him to enter a 2nd number, "Number 2"
then we'll inform him of a value
which is the sum of these 2 numbers, here, OK?
On the last line, we'll register this component as an application...
a classic Web application to access it with a browser.
So if we look inside it,
how is the request method implemented?
The request method is a string.
Internally, as we can see, it uses "call" and "answer".
If we go back to the previous example,
we see that when we made the request here, internally,
it called another component,
and not just any old one, the WAInputDialog component,
it displayed the string,
and this component will return the result to whoever requested it.
In this instance, who requested it? Our component "Adder".
So it will recuperate a value in "Value 1".
The same thing for "Value 2" and then in "inform".
If we take a look at how "inform" is implemented,
it also uses a call/answer, but on another type of component,
which is a "FormDialog".
If we do "self, call: FormDialog"
we'll display the string with an OK button to say,
"OK, he's seen the string".
So what you need to know
in all these forms of composition,
we've never talked about requests,
about http requests, about URL, parsing and settings,
we haven't talked about request routing.
We haven't made any links to the following pages, etc...
We've only talked about components,
stateful components that we can compose,
so the 3 forms of composition.
A component can encapsulate others,
a component can call another component,
and we can define workflows, strings of components in Seaside,
which is extremely powerful,
and all with the possibility of live debugging.