tags:

views:

49

answers:

2

Let's consider following problem.

There is a page that contains baskets. A basket is a component that contains a list of items such as fruits or cars or whatever.

In the page there are three baskets: car-basket, fruit-basket and all-basket. The car-basket contains cars, fruit-basket contains fruits and all-basket can contain both cars and fruits.

Initially there are items only in the car- and fruit-baskets. By clicking item in those baskets the item will be moved to the all-basket. By clicking item in the all-basket, item will be moved back to it's original basket.

Also, fruit-items and car-items are rendered differently. For instance car-item may contain a different kind of background than fruit-item. Also item may contain different kind of information. For instance car-item contains car's maximum speed and fruit-item contains the color of the fruit.

This rendering must be retained also in the all-basket.

How would you do the page with Tapestry? I do not need a full implementation. I am merely interested in the principles how that problem could be solved.

Also, for simplified implementation, can you give some estimation of how much time it would take?

+1  A: 

For a start, you'd create components for cars and fruits. The display of the cars and fruits baskets then just loops through the items, displaying a fruit/car component for each of them.

The mixed basket is a little trickier. Tapestry is not very good at dynamic structures ("dynamic behaviour, static structure"), so you'd need an if construct to render either a car or a fruit component.

<t:loop t:source="items" t:value="currentItem">
    <t:if t:test="currentCar">
       <span t:type="Car" t:car="currentCar" />
    </t:if>
     <t:if t:test="currentFruit">
       <span t:type="Fruit" t:fruit="currentFruit" />
    </t:if>
</t:loop>

A getCurrentCar() method in that component should return null when currentItem is not a car, and getCurrentFruit() should return null when the item is not a fruit.

To make things move between lists, you can just use ActionLinks with appropriate event handlers. To support AJAX, you could use Tapestry's built-in Zone functionality. To update multiple zones at a time, you can return a MultiZoneUpdate object from your event handler. (Or you could write your own, optimized client-side code.)

You should be able to set up this basic structure in very little time, how long it'll take you in total depends on how elaborate you want things to get.

Henning
A: 

Here is a continuation of Henning's approach :

<!-- render car basket -->
<t:loop t:source="carBasket" t:value="currentItem">
    <t:if t:test="currentCar">
       <span t:type="Car" t:car="currentCar" />
       <!-- TODO : eventlink for add to all basket -->
    </t:if>
</t:loop>

<!-- render fruit basket -->
<t:loop t:source="fruitBasket" t:value="currentItem">
     <t:if t:test="currentFruit">
       <span t:type="Fruit" t:fruit="currentFruit" />
       <!-- TODO : eventlink for add to all basket -->
    </t:if>
</t:loop>

<!-- render all basket -->
<t:loop t:source="allBasket" t:value="currentItem">
    <t:if t:test="currentCar">
       <span t:type="Car" t:car="currentCar" />
       <!-- TODO : eventlink for back to car basket -->
    </t:if>
     <t:if t:test="currentFruit">
       <span t:type="Fruit" t:fruit="currentFruit" />
       <!-- TODO : eventlink for back to fruit basket -->
    </t:if>
</t:loop>

In the page you would have something like this

@Property
private Item currentItem;

public Set<Item> getAllBasket(){
    return allBasket;
} 

public Set<Car> getCarBasket(){
    return carBasket;
} 

public Set<Fruit> getFruitBasket(){
    return fruitBasket;
}

public Fruit getCurrentFruit(){
   return currentItem instanceof Fruit ? (Fruit)item : null;
}

public Car getCurrentCar(){
    return curretItem instanceof Car ? (Car)item : null;
}
Timo Westkämper

related questions