Oh I get now...

I tried using "${component:myZone}.id" as the zone attribute of the link but
all the variations I tried just rendered something like this:

"[EMAIL PROTECTED]"

I couldn't work out how to access properties of the component. Any ideas?

But it gave me another idea to free my code from getCurrentZoneId method. I
am now significantly satisfied with the following solution. It makes for one
very lean POJO.

 .tml snippet:
     <t:loop t:source="myList" t:index="var:index" t:value="currentValue">
         <t:zone t:id="myZone">...${currentValue}...</t:zone>
         <t:eventlink t:event="myUpdate" t:zone="prop:myZone.clientId"
t:context="var:index">...</t:actionlink>
     </t:loop>

 .java snippet:
     @Component
     private Zone _myZone; // Getters and Setters...
     private List _myList; // Getters and Setters...
     private Object _currentValue; // Getters and Setters...

     Object onMyUpdate(index) {
         setCurrentValue(_myList.get(index));
         return _myZone;
     }

QED

Cheers,
Corin


HugoPalma wrote:
> 
> No problem, just glad i could help :o)
> 
> Regarding the component prefix, have you tried using it ? Because it
> really is just what that line says. You just have to provide the id of a
> component and the expression will resolve to the component instance.
> Example:
> 
> <t:pagelink t:id="mypagelink" page="Start">Home</t:pagelink>
> 
> <t:delegate to="component:mypagelink"/>
> 
> This would render the pagelink component twice.
> 
> Corin Lawson wrote:
>> Awesome!
>>
>> Sorry, I overlooked that one ... I'm just a noob :P
>>
>> Thanks for sharing HugoPalma.
>>
>> All that I want now is the ability do away with the currentZoneId
>> property.
>> Could someone explain the component prefix of a binding expression. The
>> Component Parameters page of the tapestry-core guide simply says:
>>
>> 'The id of another component within the same template'
>>
>> Could someone provide an example of how it's used?
>>
>>
>> HugoPalma wrote:
>>   
>>> Regarding your request for the event attribute in ActionLink. Doesn't
>>> the component EventLink solve your problem ?
>>>
>>> http://tapestry.apache.org/tapestry5/tapestry-core/ref/org/apache/tapestry/corelib/components/EventLink.html
>>>
>>> Corin Lawson wrote:
>>>     
>>>> Hi All,
>>>>
>>>> I admire Travis' ambition, but he's forgetting an ancient programming
>>>> maxim:
>>>> be lazy! By that I mean there no need to implement your own Zone
>>>> component
>>>> (or sub-component). I actually got this to work, but I'm not %100
>>>> satisfied.
>>>>
>>>> So the id attribute of zone doesn't allow property expansion; don't
>>>> despair,
>>>> use the default. The Loop component does 'unique-ify' the ids in a
>>>> predictable manner, so let's take advantage of that! All we need is a
>>>> method
>>>> to compute what the zone id is expected to be for that iteration. This
>>>> would
>>>> be possible with render variables, if it weren't the fact that the
>>>> second
>>>> iteration starts at zero!
>>>>
>>>> .tml snippet:
>>>>     <t:loop t:source="..." t:index="currentIndex"
>>>> t:value="currentValue">
>>>>         <t:zone t:id="myZone">...${currentValue}...</t:zone>
>>>>         <t:actionlink t:id="myAction" t:zone="prop:currentZoneId"
>>>> t:context="currentValue">...</t:actionlink>
>>>>     </t:loop>
>>>>
>>>> .java snippet:
>>>>     @Component
>>>>     private Zone _myZone;
>>>>
>>>>     private int _currentIndex; // Getters and Setters...
>>>>     private Object _currentValue; // Getters and Setters...
>>>>
>>>>     public String getCurrentZoneId() {
>>>>         if(_currentIndex == 0)
>>>>             return "myZone";
>>>>         return "myZone_" + (_currentIndex - 1);
>>>>     }
>>>>
>>>>     Object onAction(_currentValue) {
>>>>         setCurrentValue(_currentValue);
>>>>         return _myZone;
>>>>     }
>>>>
>>>> Note that it is important to pass the currentValue through the context
>>>> because I have used it's value inside the zone. Any property expansion
>>>> inside the zone needs to passed through the context otherwise Tapestry
>>>> (or
>>>> more specifically the Zone component) doesn't know what iteration it
>>>> is.
>>>>
>>>> Limitations:
>>>>
>>>>  (*) We are stuck with Loop's unique-ifation.
>>>>  (*) We must use the generic onAction event handler (unless the OnEvent
>>>> annotation does property expansion in the component attribute(?))
>>>>  (*) Don't go crazy with the currentValue, stick to the primitives.
>>>> Having
>>>> said that you can always pass the currentIndex through the context and
>>>> use
>>>> that to set the currentValue.
>>>>
>>>> There is a work-around these limitations. If with define an upper limit
>>>> to
>>>> the size of the Loop's source list (not an unreasonable thing to do)
>>>> then
>>>> we
>>>> could ditch the context and be verbose to the event handler methods
>>>> like
>>>> so:
>>>>
>>>>     Object onActionFromMyAction() {
>>>>         _currentIndex = 0;
>>>>         _currentValue = ...;
>>>>         return _myZone;
>>>>     }
>>>>
>>>>     Object onActionFromMyAction_0() {
>>>>         _currentIndex = 1;
>>>>         _currentValue = ...;
>>>>         return _myZone;
>>>>     }
>>>>
>>>>     Object onActionFromMyAction_1() {
>>>>         _currentIndex = 2;
>>>>         _currentValue = ...;
>>>>         return _myZone;
>>>>     }
>>>>
>>>> etc.
>>>>
>>>> In fact, it would be a fairly simple task to do this with java
>>>> instrumentation. It would be even better to have a event type attribute
>>>> on
>>>> ActionLink, so that we can specify something other than action, like:
>>>>
>>>>     Object onMyEventFromMyLink(currentIndex) {
>>>>         ...
>>>>         return _myZone;
>>>>     }
>>>>
>>>> Dear Commiters, please add an event attribute to ActionLink.
>>>>
>>>> Cheers,
>>>> Corin.
>>>>
>>>>
>>>> Travis McLeskey wrote:
>>>>   
>>>>       
>>>>> (I wasn't subscribed to the list, so I'm sorry I'm not quoting the  
>>>>> rest of the thread here.)
>>>>>
>>>>> I ran into the same problem as Adriaan: it wouldn't let me use a  
>>>>> property expansion for the zone's id attribute. The only way around  
>>>>> this that I found was to create my own MyZone component (based on  
>>>>> Tapestry's Zone.java) and add a "customId" attribute. Then, in  
>>>>> MyZone.beginRender(), I replaced this:
>>>>>
>>>>>          _clientId =  
>>>>> _pageRenderSupport.allocateClientId(_resources.getId());
>>>>>
>>>>> with something like:
>>>>>
>>>>>          if( _resources.isBound("customId") )
>>>>>              _clientId = _customId;
>>>>>          else
>>>>>              _clientId =  
>>>>> _pageRenderSupport.allocateClientId(_resources.getId());
>>>>>
>>>>> Then, I made my loop look more like this:
>>>>>
>>>>> <t:loop source="items" value="item">
>>>>>   <t:actionlink zone="myzone:${item.id}">go!</t:actionlink>
>>>>>   <t:myzone customid="myzone:${item.id}">in the zone?</t:zone>
>>>>>   <br />
>>>>> </t:loop>
>>>>>
>>>>> Which worked quite nicely, and it let me make a few other tweaks to  
>>>>> how the Zone was rendered, like making it a  instead of a <div>.
>>>>>
>>>>>
>>>>>
>>>>> However, that was only the first Zone-related hurdle. The next was  
>>>>> that I couldn't find any examples in the documentation of how to  
>>>>> actually provide the new content for the zone when the user clicks the  
>>>>> link. After a lot of time digging through the code (and learning  
>>>>> javascript!), I found the (or at least *a*) way to do it. I added this  
>>>>> method to my class:
>>>>>
>>>>>      public Object onActionFromUpdatezone(final long id) {
>>>>>          JSONObject result = new JSONObject();
>>>>>          result.put("content", "The new content for the Zone's <div>.  
>>>>> Fresh from the server!");
>>>>>          return result;
>>>>>      }
>>>>>
>>>>> (Note: I gave the ActionLink an id: "updatezone")
>>>>>
>>>>>
>>>>>
>>>>> The next problem was that Zones in Tapestry currently can't do much  
>>>>> other than query the server for new content, put that content in the  
>>>>> <div>, and then call your "show" or "update" methods, if you specified  
>>>>> them. You can't have it do something other than hit the server when  
>>>>> the link is clicked, and you can't process the content before putting  
>>>>> it in the <div>. Well, at least you can't do these things without the  
>>>>> magic of javascript. My eventual solution is probably going to break  
>>>>> in some future release of Tapestry, and it may provoke some frowns,  
>>>>> but I circumvented all of the Zone-specific javascript code in  
>>>>> Tapestry be redefining Tapestry.initializeZones. The javascript below  
>>>>> is for an ActionLink that works as an expand/collapse button for the  
>>>>> Zone. The first time you expand the zone, it downloads the content  
>>>>> from the server and stores it in memory. After that, it doesn't need  
>>>>> to hit the server again. Note that this code doesn't support the inner  
>>>>> "t-zone-update" <div> that Tapestry's built-in javascript supports.
>>>>>
>>>>>
>>>>> MyObj = {
>>>>>    linkZone: function (link, zone) {
>>>>>      zone = $(zone);
>>>>>      link = $(link);
>>>>>      var expanded = false;
>>>>>      var origHTML = zone.innerHTML;
>>>>>      var fullHTML;
>>>>>
>>>>>      link.onclick = function(event) {
>>>>>        if( expanded ) {
>>>>>          zone.innerHTML = origHTML;
>>>>>          link.innerHTML = "expand";
>>>>>          expanded = false;
>>>>>        } else {
>>>>>          if( !zone.everPopulated ) {
>>>>>            var successHandler = function(transport) {
>>>>>              var response = transport.responseText;
>>>>>              fullHTML = eval("(" + response + ")").content;
>>>>>              zone.innerHTML = fullHTML;
>>>>>            };
>>>>>            var request = new Ajax.Request(link.href, { onSuccess :  
>>>>> successHandler });
>>>>>            zone.everPopulated = true;
>>>>>          } else {
>>>>>            zone.innerHTML = fullHTML;
>>>>>          }
>>>>>          link.innerHTML = "collapse"
>>>>>          expanded = true;
>>>>>        }
>>>>>        return false;
>>>>>      };
>>>>>    }
>>>>> };
>>>>>
>>>>> Tapestry.initializeZones = function(zoneSpecs, linkSpecs) {
>>>>>    $A(linkSpecs).each(function (spec)
>>>>>    {
>>>>>        MyObj.linkZone(spec[0],spec[1]);
>>>>>    });
>>>>> };
>>>>>
>>>>>
>>>>>
>>>>> Hope that helps!
>>>>> Travis
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> On Feb 8, 2008, at 11:40 PM, Travis McLeskey wrote:
>>>>>
>>>>>     
>>>>>         
>>>>>> When an ActionLink and Zone appear together in a loop like this:
>>>>>>
>>>>>> <t:loop source="items" value="item">
>>>>>>  <t:actionlink zone="myzone">go!</t:actionlink>
>>>>>>  <t:zone t:id="myzone">in the zone?</t:zone>
>>>>>>  <br />
>>>>>> </t:loop>
>>>>>>
>>>>>> Clicking the "go!" link from any iteration only affects the Zone  
>>>>>> from the first iteration. How do I connect each ActionLink to its  
>>>>>> corresponding Zone? I tried injecting the Zone into the java class  
>>>>>> and then using zone="${thezone.id}" in the actionlink, but then each  
>>>>>> ActionLink was connected to the Zone from the *previous* iteration.
>>>>>>
>>>>>> Thanks!
>>>>>> Travis
>>>>>>
>>>>>>       
>>>>>>           
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: [EMAIL PROTECTED]
>>>>> For additional commands, e-mail: [EMAIL PROTECTED]
>>>>>
>>>>>
>>>>>
>>>>>     
>>>>>         
>>>>   
>>>>       
>>>     
>>
>>   
> 
> 

-- 
View this message in context: 
http://www.nabble.com/T5%3A-ActionLink-Zone-components-inside-a-loop-tp15374193p15480337.html
Sent from the Tapestry - User mailing list archive at Nabble.com.


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to