Re: T5: ActionLink/Zone components inside a loop (solved, better)
Corin Lawson wrote: 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. But in cases like mine, where the zone comes after the links in the markup (which should be a quite common case) - the problem sadly remains, since the name of the zone can't be determined before rendering it :-( -- View this message in context: http://www.nabble.com/T5%3A-ActionLink-Zone-components-inside-a-loop-tp15374193p18115824.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]
Re: T5: ActionLink/Zone components inside a loop (solved, better)
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=StartHome/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
Re: T5: ActionLink/Zone components inside a loop (solved, better)
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=StartHome/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
Re: T5: ActionLink/Zone components inside a loop (solved, better)
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
Re: T5: ActionLink/Zone components inside a loop (solved, better)
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
Re: T5: ActionLink/Zone components inside a loop (solved, better)
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