Event Bubbling

If a component's event handler method returns true, the handling of that event is aborted. Otherwise, the event "bubbles up".

"Bubbling up" means that if there are no more matching event handlers in the component (see the Multiple Method Matches example) then the component will trigger the same event in its containing component. The containing component in this example is the page.

Here we have 4 instances of MyComponent. MyComponent renders an EventLink with the event name we give. We give 4 event names: EventA, EventB, EventC, and EventD.

Server-side, MyComponent handles 3 events: EventA, EventB, and EventC; and the page handles 6 events: EventA, EventB, EventC, EventD, EventE, and EventX.
EventA
EventB
EventC
EventD
References: Event Bubbling.

Home

EventBubbling.tml


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- We need a doctype to allow us to use special characters like &nbsp; 
     We use a "strict" DTD to make IE follow the alignment rules. -->
     
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
<head>
    <link rel="stylesheet" type="text/css" href="${context:css/examples/examples.css}"/>
</head>
<body>
    <h1>Event Bubbling</h1>
    If a component's event handler method returns <em>true</em>, the handling of that event is aborted. Otherwise, the event "bubbles up".<br/><br/>

    "Bubbling up" means that if there are no more matching event handlers in the component (see the Multiple Method Matches example) 
    then the component will trigger the same event in its containing component. The containing component in this example is the page.<br/><br/>

    Here we have 4 instances of MyComponent. MyComponent renders an EventLink with the event name we give. We give 4 event names: EventA, EventB, EventC, and EventD.<br/><br/>
    Server-side, MyComponent handles 3 events: EventA, EventB, and EventC; and the page handles 6 events: EventA, EventB, EventC, EventD, EventE, and EventX.<br/>

    <div class="eg">
        <t:if t:test="pageMessage">
            <span style="color:red;">${pageMessage}<br/><br/></span>
        </t:if>

        <a t:type="examples/component/mycomponent" t:eventname="EventA" href="#">EventA</a><br/>
        <a t:type="examples/component/mycomponent" t:eventname="EventB" href="#">EventB</a><br/>
        <a t:type="examples/component/mycomponent" t:eventname="EventC" href="#">EventC</a><br/>
        <a t:type="examples/component/mycomponent" t:eventname="EventD" href="#">EventD</a><br/>
    </div>
    
    References: 
    <a href="http://tapestry.apache.org/component-events.html#ComponentEvents-EventBubbling">Event Bubbling</a>.<br/><br/>
    
    <a t:type="pagelink" t:page="Index" href="#">Home</a><br/><br/>

    <t:sourcecodedisplay src="/web/src/main/java/jumpstart/web/pages/examples/component/EventBubbling.tml"/>
    <t:sourcecodedisplay src="/web/src/main/java/jumpstart/web/pages/examples/component/EventBubbling.java"/>
    <t:sourcecodedisplay src="/web/src/main/java/jumpstart/web/css/examples/examples.css"/>
    <t:sourcecodedisplay src="/web/src/main/java/jumpstart/web/components/examples/component/MyComponent.tml"/>
    <t:sourcecodedisplay src="/web/src/main/java/jumpstart/web/components/examples/component/MyComponent.java"/>
</body>
</html>

EventBubbling.java


package jumpstart.web.pages.examples.component;

import org.apache.tapestry5.PersistenceConstants;
import org.apache.tapestry5.annotations.Persist;
import org.apache.tapestry5.annotations.Property;

public class EventBubbling {

    // Screen fields

    @Property
    @Persist(PersistenceConstants.FLASH)
    private String pageMessage;

    // The code
    
    void onEventA() {
        pageMessage = "EventA bubbled up to the page.";
    }

    void onEventB() {
        throw new IllegalStateException("Cannot happen because MyComponent aborts handling of EventB.");
    }

    void onEventC() {
        throw new IllegalStateException("Cannot happen because MyComponent aborts handling of EventC.");
    }

    void onEventD() {
        pageMessage = "EventD bubbled up to the page.";
    }

    void onEventE() {
        pageMessage = "EventE bubbled up to the page.";
    }

    void onEventX() {
        pageMessage = "EventX bubbled up to the page.";
    }
}

examples.css


body            { font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 13px; font-weight: normal; color: #333; line-height: 17px; }
h1              { font-size: 26px; line-height: 20px; } /* For IE 7 */
form            { margin: 0; }                  

.eg             { margin: 20px 0; padding: 20px; color: #888; 
                    border: 1px solid #ddd; border-radius: 4px; -webkit-border-radius: 4px; -mox-border-radius: 4px; }

a               { text-decoration: none; color: #3D69B6; }
a:hover         { text-decoration: underline; }

/* For BeanDisplay */
.eg dl          { margin: 0; color: #333; }
.eg dl.t-beandisplay dd.id  { display: inline; margin-left: 0px; }  /* IE 7 hack */

MyComponent.tml


<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
<t:content>
    <a t:type="eventlink" t:event="prop:eventname" href="#"><t:body/></a>
    <span style="color:red">${message}</span>
</t:content>
</html>

MyComponent.java


package jumpstart.web.components.examples.component;

import org.apache.tapestry5.BindingConstants;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.PersistenceConstants;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.annotations.Persist;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.ioc.annotations.Inject;

/**
 * MyComponent contains an EventLink and a message that is set up by whichever event handler method is triggered.
 */
public class MyComponent {

    // Parameters
    
    @Parameter(defaultPrefix = BindingConstants.LITERAL)
    @Property
    private String eventName; 
    
    // Screen fields

    @Property
    @Persist(PersistenceConstants.FLASH)
    private String message;

    // Generally useful bits and pieces

    @Inject
    private ComponentResources componentResources;

    // The code

    boolean onEventA() {
        message = "MyComponent handles EventA then bubbles it up.";
        
        // Let EventA bubble up.
        return false;
    }

    boolean onEventB() {
        message = "MyComponent handles EventB then aborts its handling.";
        
        // Abort handling of EventB.
        return true;
    }

    boolean onEventC() {
        message = "MyComponent handles EventC and triggers EventX in its place.";

        // Trigger the event "eventX" on myself which will then bubble up.
        componentResources.triggerEvent("eventX", null, null);

        // Abort handling of EventC.
        return true;
    }
    
    // We deliberately don't handle EventD, so it will bubble straight up.

}