I am working on a project where we need to be able to do a Facebook share on a particular page for an event from multiple places within a web application. Putting this functionality into a Tapestry component makes it easy to call it from where ever it is needed and the code makes for a nice concise example of how components work in Tapestry.
In Tapestry components consist of two parts. The first part is the .tml file and the second is the .java file. In general the .tml file is concerned with how things render out in HTML and the .java file is concerned with the programatic side of things and retrieving the data.
The end result is going to be a tag that we can use in other .tml files that will look like this:
<t:facebookshare event="myEvent"/>
First lets look at the .tml file. This file is saved under:
/src/main/resources/com/example/myapp/components/FacebookShare.tml
<t:container xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd" > <a href="#" onclick="window.open('http://www.facebook.com/sharer.php?u=${facebookShareURL}&display=popup','fbshare','menubar=0,location=0,resizable=1,width=700,height=350')"> Please share this event on Facebook </a><br/> </t:container>
The ${facebookShareURL} is what will call getFacebookShareUrl() on the java class in order to fill out the component with the data it needs. In this case it will be an encoded URL.
The .java component file is saved in:
/src/main/java/com/example/myapp/components/FacebookShare.java
import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import javax.persistence.Transient; import net.xeric.register.entities.Event; import org.apache.tapestry5.Link; import org.apache.tapestry5.annotations.Parameter; import org.apache.tapestry5.annotations.Property; import org.apache.tapestry5.ioc.annotations.Inject; import org.apache.tapestry5.services.PageRenderLinkSource; public abstract class FacebookCommon { @Inject private PageRenderLinkSource linkSource; @Parameter(required=true) @Property private Event event; public String getFacebookShareURL() { Link link = linkSource.createPageRenderLinkWithContext("EventInfo", event); String linkURL = ""; try { linkURL = URLEncoder.encode(link.toAbsoluteURI(),"UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return linkURL; } }
I have a page called EventInfo that shows all the information about a particular event. So this component takes an event as a parameter and then constructs the link to share on the EventInfo page.
This is how we tell Tapestry that we have a required parameter that needs to be bound to an event:
@Parameter(required=true) @Property private Event event;
That means that when we use the component like this:
<t:facebookshare event="myEvent"/>
Tapestry is going to expect the parameter event to be bound to an event object.
Line 42 has the code that constructs our link back to the EventInfo page using the context of the event that we’ve passed in as a parameter to the component.
Link link = linkSource.createPageRenderLinkWithContext("EventInfo", event); String linkURL = ""; try { linkURL = URLEncoder.encode(link.toAbsoluteURI(),"UTF-8");
The rest of the getFacebookShareURL method simply encodes the URL as a string and returns it. This is the value that replaces the ${facebookShareUrl} in the template when the component is rendered.