Embedding Subcomponents

It is common for a component to display instances of other components while rendering itself. It does this by passing them into the #render: method of WARenderCanvas. For example, this #renderContentOn: method simply renders a heading and then displays a counter component immediately below it:

These instances, or "subcomponents" are usually instance variables of the component that is "embedding" them. They are commonly created as part of the parent’s #initialize method:

initializesuperinitialize.myCounter:=WACounternew.

They may also be stored in a collection. One fairly common pattern is to keep a lazily initialized dictionary of subcomponents that match a collection of model items. For example, if you wanted a BudgetItemRow subcomponent for each member of budgetItems, you might do something like this:

Each parent component must implement a #children method that returns a collection of all of the subcomponents that it might display on the next render. For the above two examples, #children might look like this:

children^Arraywith:myCounter.

or this:

children^selfbudgetItemscollect:[:each|selfrowForItem:each].

If a subcomponent makes a #call: to another component, that component will appear in place of the subcomponent. In the first example, if myCounter made a #call: to DateSelector, that DateSelector would appear in the context of the counter’s parent, with the ’My Counter’ heading above it.

Since a subcomponent has not been #call:’d, in general #answer: is a no-op. However, the parent may attach an #onAnswer: block to the subcomponent to be notified if it sends #answer:. This allows one component to be used both from #call: and through embedding. For example: