Barracuda Component Model Tutorial - HelloWorld 1b

<<|Preface|HelloWorld 1|1a|1b|2|2a|2b|3|4|>>

barracuda.gif (11456 bytes) Hello World 1b - this example demonstrates how a model can pass back more than just Strings. In this case we also return Nodes and BComponents.

Returning a Node

In general, this example is very similar to the HelloWorld1 servlet.  There are, however, a couple of key differences.

First of all, notice that in this example we are using two templates: one for the Body and one for the Footer. If you examine the source for HelloWorld1b, you will see how the model loads and returns a complex Node for the footer. The actual code looks somethign like this:

else if (key.equals("Footer")) {
    XMLObject footer = xmlcFactory.create(HelloWorld1b_footerHTML.class);
    Node footerNode = footer.getElementById("Footer");
    return vc.getElementFactory().getDocument().importNode(footerNode, true);
}

Let's talk about what is actually going on here. Basically, when the component encounters the directive requesting the footer data, the code listed above gets invoked. We start by loading the Footer page and grabbing a reference to the actual Footer node (specified by the "Footer" id).

Now, before we return the node, we must first import it into the current document (since the node is currently a child of the Footer page). To do this, we get a copy of the ElementFactory from the ViewContext. The element factory provides the necessary link to the document we are actually working on; we invoke importNode() and then just return the result.

So what happened in the component to make it work? Well, the component requested the data from the model when it encountered the following node in the template:

<p class="Dir::Get_Data.HelloWorld.Footer" align="center">[Footer goes here]</p>

When the model returns data of type Node, it discards the template node and uses the models node instead. Pretty simple!


Returning a BComponent

We also return a BComponent in this example, which you seen in final form as an email link in the upper right hand of the page. Although here the component returned is intentionally quite simple (the BLink component is just a simple extension of BAction) it demonstrates the basic functionality quite nicely.

Let's start by looking at the model source. The line in question looks something like this:

else if (key.equals("Header"))
    return new BLink("Email Christian", "mailto:...@lutris.com");

Here we can see that when the component requests data for the Header key, we instantiate a BLink component and return that. The first parameter represents the text of the link; the second param represents the URL.

When the BLink is rendered,  it makes sure everything gets put into the proper format and displayed correctly. Now, we could obviously return the string representation of the email link if we desired, but its generally a lot easier to let the component take care of that for us, especially when the components are intelligent enough to render themselves properly in multiple *ML formats.

Now, you may be thinking, "Dang, this is cool! What actually goes on behind the scenes to make this work?" (If you're not thinking this, skip to the next section). Ok, you're still reading so I assume you actually want to know. Basically, when a component finds that the data returned from its model implements BComponent, it says "Oh, I have an object that knows how to render itself in the DOM. Great, that means I don't have to worry about it." All the parent component has to do is make sure of two things:

  1. first, the views for the returned component must be part of the DOM so that when the page is rendered the changes made by the component will be reflected (in the case of our BLink, there really is no view yet so the parent component creates a default node using the ViewContext and adds it in)

  2. second, the returned component must be added to the parent component hierarchy so that it too will actually get a chance to render. The component does this by adding it in as a child component, while keeping track of it at the same time so that it can be removed once the render process is completed.

As long as the second condition is met, the component returned from the model will get rendered (along with any other children the parent component might contain), allowing it to update the portions of the DOM it is bound to. Assuming the first condition is also met (that the DOM it is updating is part of the master template we're working on), then the data contained in the child component will ultimately be reflected in the page that gets returned to the user.

Whew! If that description leaves you still feeling a little fuzzy, don't worry! All you really need to know is that a Model can return Node, BComponent, or String data and the components should always be able to handle it. Very cool.

Click here to return to the Barracuda Component Model Tutorial page.

For all the latest information on Barracuda, please refer to http://barracuda.enhydra.org
Questions, comments, feedback? Let us know...
Copyright 1997-2002 Lutris Technologies, Inc. All rights reserved.