The idea of passing blocks to layout sounds good to customize content in different areas. For event handling I still have to either 1) introduce a super class for all page classes to handle the event and trigger the refresh 2) or add the event handler on almost all pages I have.
So inheritance seems to be a more pragmatic choice to me. I have also come across template inheritance feature of Tapestry: http://tapestry.apache.org/component-templates.html Creating the layout as the super class of pages and use both java and template inheritance looks like the most pragmatic choice (no need to pass around blocks, but I can replace the parts in the parent template) This means the following changes to the code I posted originally: *Page: ShowSweepstakes.tml file:* <t:extend xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd" xmlns:p="tapestry:parameter"> <t:replace id="LayoutBody"> <t:sweepstake.ShowSweepstakes /> </t:replace> </t:extend> *Layout.tml component* <t:extend xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd" xmlns:p="tapestry:parameter"> <t:replace id="FullWidthLayoutBody"> <div id="layout-container" class="container"> <div class="row"> <t:extension-point id="LayoutBody" /> </div> </div> </t:replace> </t:extend> *FullWidthLayout.tml component:* <html><body> <span t:type="zone" t:id="totalPointsZone">${user.totalPoints}</span> <t:extension-point id="FullWidthLayoutBody" /> </body> </html> On the java side the page classes has to also extend the Layout class. On Sat, 16 Feb 2019 at 13:11, Chris Poulsen <mailingl...@nesluop.dk> wrote: > Hmm, generally speaking it is the responsibility of the container (page) to > coordinate its children. > > At work we have a couple of places where certain areas of the layout needs > to be interacted with from the pages. We have chosen to handle the matter > with block parameters in the layout. Pages that need to have "stuff" in the > layout use the parameters to add their extra things in the available areas. > > In your case you could add a (page) block that contains the zone with the > stuff for the layout, when the page receives the event, the zone is > updated. > > You could probably also obtain the component resources of the layout > component and manually trigger an event from the page, but that seems less > nice to me. > > -- > Chris > > > > On Fri, Feb 15, 2019 at 2:53 PM Balázs Palcsó <palcso.bal...@gmail.com> > wrote: > > > Hi Chris, > > > > Yes, that seems to be correct that the layout components with <t:body /> > > (FullWidthLayout and Layout) are not represented in the component > > container tree (ComponentPageElement.getContainerElement();) where the > > event bubbling up happening. > > > > Is there any tapestry design pattern to come over this? > > > > Most of my pages have the same layout (header, menu, footer, etc) that's > > why I use these Layout components with the <t:body />, but the > > FullWidthLayout has a zone that would need to be refreshed too for a > number > > of events. > > > > Thanks, > > Balázs > > > > > > > > On Fri, 15 Feb 2019 at 09:49, Chris Poulsen <mailingl...@nesluop.dk> > > wrote: > > > > > Hi > > > > > > I haven't looked much into this, but my guess is that your layout is > > using > > > t:body and that confuses things? > > > > > > As far as I understand t.body makes a component able to wrap its > template > > > around something in its containing component. - That probably means > that > > > your stuff wrapped in the layout isn't a child component of the layout, > > so > > > your event does not bubble to the layout. > > > > > > You can inspect the tapestry component model of the page at runtime > > (using > > > a debugger) to see how the actual components are connected. > > > > > > If it turns out that your layout does not participate the expected > place > > in > > > your component hierarchy, you could expose various aspects of the > layout > > > using parameters, for example allowing access to the zone or pick some > > > other construct that matches your needs. > > > > > > -- > > > Chris > > > > > > > > > > > > On Thu, Feb 14, 2019 at 10:24 PM Balázs Palcsó < > palcso.bal...@gmail.com> > > > wrote: > > > > > > > Hello, > > > > > > > > Refreshing totalPointsZone from the FullWidthLayout is not working > when > > > > participateInSweepstake async eventlink is clicked > > > > in sweepstake.ShowSweepstake nested component. > > > > > > > > Any suggestions how to get both the participateInSweepstakeZone and > the > > > > totalPointsZone refreshed when <t:EventLink > > > event="participateInSweepstake" > > > > context="${sweepstake.id}" async="true">Participate is > > > > clicked</t:EventLink> > > > > > > > > *Here is the relevant code snippets from the app:* > > > > > > > > *Page: ShowSweepstakes.tml file:* > > > > <html t:type="layout" xmlns:t=" > > > > http://tapestry.apache.org/schema/tapestry_5_4.xsd"> > > > > <t:sweepstake.ShowSweepstakes /> > > > > </html> > > > > > > > > *sweepstake.ShowSweepstakes.tml component:* > > > > <t:container> > > > > <loop> > > > > <t:sweepstake.ShowSweepstake sweepstake="sweepstake" /> > > > > </loop> > > > > </t:container> > > > > > > > > *sweepstake.ShowSweepstake.tml component:* > > > > <t:zone t:id="participateInSweepstakeZone" > > > > id="prop:participateInSweepstakeZoneId"> > > > > <t:if test="notParticipatedYet"> > > > > <t:EventLink event="participateInSweepstake" > > context="${ > > > > sweepstake.id}" async="true" class="btn btn-danger btn-lg"> > > > > Participate for > > > > ${sweepstake.priceToParticipateInPoints} points > > > > </t:EventLink> > > > > <p:else> > > > > <button type="button" class="btn btn-danger btn-lg" > > > > disabled="disabled">You're already participating</button> > > > > </p:else> > > > > </t:if> > > > > </t:zone> > > > > > > > > *ShowSweepstake .java:* > > > > public class ShowSweepstake { > > > > @CommitAfter > > > > void onParticipateInSweepstake(final Sweepstake sweepstake) { > > > > .... > > > > > > > > componentResources.triggerEvent(ComponentEvents.REFRESH_TOTAL_POINTS, > > > null, > > > > null); > > > > if (request.isXHR()) { > > > > > > ajaxResponseRenderer.addRender(participateInSweepstakeZone); > > > > } > > > > } > > > > > > > > *Layout.tml component* > > > > <html t:type="FullWidthLayout"> > > > > <div id="layout-container" class="container"> > > > > <div class="row"> > > > > <t:body /> > > > > </div> > > > > </div> > > > > </html> > > > > > > > > *FullWidthLayout.tml component:* > > > > <html><body> > > > > *<span t:type="zone" > > > t:id="totalPointsZone">${user.totalPoints}</span>* > > > > <t:body /> > > > > </body> </html> > > > > > > > > *FullWidthLayout .java component* > > > > public class FullWidthLayout { > > > > *@OnEvent(ComponentEvents.REFRESH_TOTAL_POINTS)* > > > > private void refreshTotalPoints() { > > > > ajaxResponseRenderer.addRender(totalPointsZone); > > > > } > > > > } > > > > > > > > Thanks, > > > > Balazs > > > > > > > > > >