Let me try…

The t:id parameter defines the component id, i.e. the "name" of the component 
in your template, which you can use for injecting the component to your 
component class:

tml:
> <t:zone t:id="myzone"></t:zone>

class:
> @InjectComponent
> private Zone myzone;

Mostly it's enough for you to specify just t:id. Each zone with a t:id gets a 
generated, unique "id" attribute. If your zone "myzone" is rendered only once 
the id attribute will be identical to the t:id attribute that it has been 
generated from.

I'll illustrate the render process and what gets initialized vie JavaScript. In 
the first example I'll show when and why you don't need to specify the 
additional id attribute to t:zone. In the second example I'll show when you 
absolutely need to specify both.

Example #1:

page tml:

> <t:zone t:id="myzone"></t:zone>
> <t:actionLink t:id="myLink" t:zone="myzone>update zone</t:actionLink>
> 
> <t:block id="lazyContent"><p>updated content</p></t:block>

page class:

> @Inject
> private AjaxResponseRenderer ajax;
> 
> @Inject
> private Block lazyContent;
> 
> void onActionFromMyLink() {
> 
>     ajax.addRenderer("myzone", lazyContent);
> }

1. The page is called for the first time
2. The zone "myzone" is rendered, its id attribute will be also "myzone".
3. The actionLink is rendered and a Tapestry JavaScript init-method will be 
prepared with the following configuration JSON:
{
    "inits": [
        {
            "linkZone": {
                "linkId": "myLink",
                "zoneId": "myzone"
            }
        }
    ]
}
       --> See the Tapestry source of ClientBehaviorSupportImpl.java "linkZone" 
method for more details.
4. The client-side JS code will look for an element with the exact id of 
"myzone" to trigger the zone update as soon as the link is clicked.
5. User clicks on the link, onActionFromMyLink is called and a zone refresh for 
the zone with the id "myzone" will be sent to the client. The id ("myzone") 
must still be equal to the id in the DOM.

Example #2:

page tml:

> <t:zone t:id="wrapperZone">
>     <t:zone t:id="myzone" id="myzone"></t:zone>
>     <t:actionLink t:id="myLink" t:zone="myzone>update inner 
> zone</t:actionLink>
> </t:zone>
> <t:actionLink t:id="wrapperUpdate" t:zone="wrapperZone >update 
> wrapper</t:actionLink>
> <t:block id="lazyContent"><p>updated content</p></t:block>


page class:

> @Inject
> private AjaxResponseRenderer ajax;
> 
> @Inject
> private Block lazyContent;
> 
> @InjectComponent
> private Zone wrapperZone;
> 
> void onActionFromMyLink() {
> 
>     ajax.addRenderer("myzone", lazyContent);
> 
> void onActionFromWrapperUpdate() {
> 
>     ajax.addRenderer("wrapperZone", wrapperZone);
> }

This time "myzone" is inside another zone. And as I said earlier the id 
attribute of a zone is only equal to the t:id attribute if the zone is only 
rendered once. After you click the "update wrapper" action link the inner zone 
"myzone" will render again and its id will not be equal to "myzone" (it's going 
to be something like myzone_012312abc) unless you specify the parameter 
yourself. This way it's also your responsibility to make sure this id is only 
existing once in your DOM.

The 5 steps from the first example stay the same for the rendering of the 
wrapper zone's body. Your actionlink (or whatever component you're using, e.g 
jquery.slider) will always bind on the same client-side zoneId, which is 
"myzone", because that's what you've specified as its t:zone parameter.

So there are multiple solutions to this problem:

1. You add id="myzone" to your inner zones to make sure the client side id 
attribute is always what you expect.
2. You make the t:zone parameter value a property that is evaluated during 
rendering. So instead of t:zone="myzone" (which is a literal binding) you 
specify t:zone="prop:currentZoneId" and add a corresponding getter in the java 
code:

> @InjectComponent
> private Zone myzone;
> 
> public String getCurrentZoneId() {
>     myzone.getClientId();
> }

Solution #2 brings another caveat: If the actionLink from my example would be 
specified in the template before the zone this wouldn't work. The zone's 
clientId would be "null" because the zone hasn't been rendered, yet… You could 
add some more advanced tricks with Heartbeats and @HeartbeatDeferred but… I 
guess you'll just stick with solution #1 :-)

I'm sure the upcoming refactorings (an euphemism?) in tapestry.js will make it 
better and easier!

tl;dr

Use t:id AND id on zones if it's a nested zone, since the client-side id would 
not be predictable and watch out you have no duplicate ids in you DOM, 
otherwise use only t:id

Cheers,
Christian



Am 10.08.2012 um 00:34 schrieb bhorvat:

> Well like it says in the subject, why should we specify both normal id and
> the t:id. I know that the latter is for the tapestry where the first one is
> for the client, but why is not that set by default in tapestry if it is that
> important, and I take it that it is because some of my code wont work
> without. For example 
> 
> <t:form>
>         <t:jquery.slider t:id="percentageSlider" t:value="percentage"
> t:zone="zonePercentage"
>                                                 t:params="sliderParams" />
> </t:form> 
> <t:zone t:id="zonePercentage" id="zonePercentage" t:update="show">
>        <div class="itcTxt">${percentage}%</div> 
> </t:zone> 
> 
> without id="zonePercentage" the event wont be triggered. 
> 
> thanks all 
> cheers
> 
> 
> 
> --
> View this message in context: 
> http://tapestry.1045711.n5.nabble.com/Why-should-we-specify-t-id-and-id-for-the-zone-tp5715208.html
> Sent from the Tapestry - User mailing list archive at Nabble.com.
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
> For additional commands, e-mail: users-h...@tapestry.apache.org
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
For additional commands, e-mail: users-h...@tapestry.apache.org

Reply via email to