Re: [T5.3] Passing page activation context to a component
Man, thank you! In case somebody else will search for this answer before reading http://tapestry.apache.org/environmental-services.html here is a sample code: Index.java == @Inject private Environment environment; private MyComponentContext myComponentContext; public void setupRender() { environment.push(MyComponentContext.class, new MyComponentContext(myString, myInteger)); } public void afterRender() { environment.pop(MyComponentContext.class); } MyComponentContext.java == public class MyComponentContext { String myString; Integer myInteger; public MyComponentContext(String myString, Integer myInteger) { this.myString= myString; this.myInteger= myInteger; } // getters and setters } MyComponent.java == public class MyComponent { @Environmental private MyComponentContext myComponentContext; public String someMethod() { String justSomething = myComponentContext.getMyString(); return Hello + justSomething; } } Cheers, borut 2011/8/24 Steve Eynon steve.ey...@googlemail.com As soon as one component pops the object(s) Ahh - that's why there's an Environement.peek() !!! Or, in your component, you could just annotate the Object with @Environmental, e.g. @Environmental private MyTwoStrings ss; Steve. -- Steve Eynon On 24 August 2011 21:33, Borut Bolčina borut.bolc...@gmail.com wrote: 2011/8/24 Steve Eynon steve.ey...@googlemail.com If the component needs 2 string parameters to function, then it needs 2 string parameters! (Much like if a method needs 2 strings, then you need to pass 2 strings.) Well, yes :-) Other alternatives are dependent on re-usability requirements: a) If the 2 strings are always used together then wrap them in a value object and pass that (you can pass anything as Component parameters). Goes without saying - OO style. b) If the component is deeply nested and / or the strings need to be available to multiple components (and you're certain they'll always exist) then you could push them on the Environmental stack and not pass any parameters - just have the component query the stack. Wouldn't that work just for one component? As soon as one component pops the object(s) from the Environment stack, others won't have it (them) anymore? Thanks, borut Steve. -- Steve Eynon On 24 August 2011 18:07, Borut Bolčina borut.bolc...@gmail.com wrote: Hi, if a component needs to have its parent's activation context (say two strings), is the preffered way to pass it as parameters or is there a less code way? The solution must not use a session. Cheers, Borut - 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
[T5.3] Passing page activation context to a component
Hi, if a component needs to have its parent's activation context (say two strings), is the preffered way to pass it as parameters or is there a less code way? The solution must not use a session. Cheers, Borut
Re: [T5.3] Passing page activation context to a component
If the component needs 2 string parameters to function, then it needs 2 string parameters! (Much like if a method needs 2 strings, then you need to pass 2 strings.) Other alternatives are dependent on re-usability requirements: a) If the 2 strings are always used together then wrap them in a value object and pass that (you can pass anything as Component parameters). b) If the component is deeply nested and / or the strings need to be available to multiple components (and you're certain they'll always exist) then you could push them on the Environmental stack and not pass any parameters - just have the component query the stack. Steve. -- Steve Eynon On 24 August 2011 18:07, Borut Bolčina borut.bolc...@gmail.com wrote: Hi, if a component needs to have its parent's activation context (say two strings), is the preffered way to pass it as parameters or is there a less code way? The solution must not use a session. Cheers, Borut - To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org For additional commands, e-mail: users-h...@tapestry.apache.org
Re: [T5.3] Passing page activation context to a component
2011/8/24 Steve Eynon steve.ey...@googlemail.com If the component needs 2 string parameters to function, then it needs 2 string parameters! (Much like if a method needs 2 strings, then you need to pass 2 strings.) Well, yes :-) Other alternatives are dependent on re-usability requirements: a) If the 2 strings are always used together then wrap them in a value object and pass that (you can pass anything as Component parameters). Goes without saying - OO style. b) If the component is deeply nested and / or the strings need to be available to multiple components (and you're certain they'll always exist) then you could push them on the Environmental stack and not pass any parameters - just have the component query the stack. Wouldn't that work just for one component? As soon as one component pops the object(s) from the Environment stack, others won't have it (them) anymore? Thanks, borut Steve. -- Steve Eynon On 24 August 2011 18:07, Borut Bolčina borut.bolc...@gmail.com wrote: Hi, if a component needs to have its parent's activation context (say two strings), is the preffered way to pass it as parameters or is there a less code way? The solution must not use a session. Cheers, Borut - To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org For additional commands, e-mail: users-h...@tapestry.apache.org
Re: [T5.3] Passing page activation context to a component
As soon as one component pops the object(s) Ahh - that's why there's an Environement.peek() !!! Or, in your component, you could just annotate the Object with @Environmental, e.g. @Environmental private MyTwoStrings ss; Steve. -- Steve Eynon On 24 August 2011 21:33, Borut Bolčina borut.bolc...@gmail.com wrote: 2011/8/24 Steve Eynon steve.ey...@googlemail.com If the component needs 2 string parameters to function, then it needs 2 string parameters! (Much like if a method needs 2 strings, then you need to pass 2 strings.) Well, yes :-) Other alternatives are dependent on re-usability requirements: a) If the 2 strings are always used together then wrap them in a value object and pass that (you can pass anything as Component parameters). Goes without saying - OO style. b) If the component is deeply nested and / or the strings need to be available to multiple components (and you're certain they'll always exist) then you could push them on the Environmental stack and not pass any parameters - just have the component query the stack. Wouldn't that work just for one component? As soon as one component pops the object(s) from the Environment stack, others won't have it (them) anymore? Thanks, borut Steve. -- Steve Eynon On 24 August 2011 18:07, Borut Bolčina borut.bolc...@gmail.com wrote: Hi, if a component needs to have its parent's activation context (say two strings), is the preffered way to pass it as parameters or is there a less code way? The solution must not use a session. Cheers, Borut - 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
Re: Activation context for a component?
Hey... I did a little follow-up on this and decided to create an event-safe loop that can restore the state of the loop variable using the page activation context. It's not quite perfect, but it's good enough for my needs right now. For my application, the resulting code ended up looking much cleaner than the version that used only the event's context to restore the state. It works like this: 1) Replace your t:loop component with t:safeloop You should specify the t:id parameter... you'll need to know it for step 3. 2) Provide an encoder for the loop value. This parameter is optional for t:loop but required for t:safeloop. However, only toClient() needs to be implemented. 3) Annotate your loop value with @LoopValue(loopid) instead of @Property, where loopid is the t:id specified for the t:safeloop. The t:safeloop component stores the state, and @LoopValue creates a special getter that can restore the state. Unfortunately, there are some additional requirements that I'd like to remove: 1) The loop source cannot be initialized by lifecycle methods (e.g. @BeginRender), since they won't get called. 2) You must include @Inject ComponentResources res; in your component in order for the code generated by @LoopValue to compile. 3) The underlying page must provide simple (one-line) boilerplate onPassivate and onActivate methods, which can be provided by inheriting from a superclass. 4) Care must be taken if you want to also use the page activation context for other purposes. So far, this is working very well for my application. I haven't tested its compatibility with the formEncode feature of the normal Loop component. If other people are interested, I'm willing to share the source code... but I probably won't have time to provide much support. -Nathan On Tue, Feb 16, 2010 at 11:08 PM, Nathan Kopp nathan0...@nathankopp.comwrote: Probably the tip I needed was this: When using an EventLink inside a loop, be sure that your event handling method does not refer to any loop variable either directly or indirectly. Especially be cautions of referring to parameters that may have been bound to any loop variable or a field of a loop variable. If you avoid referring to such parameters in the eventlink's event handler (and pass the information to that method using the context instead), Tapestry will not attempt to process the parameter binding, and therefore no problem will be caused by the null loop variable. I would have found this most easily if it were located in the primary documentation for either EventLink or Loop in the component reference. Tapestry's stack trace actually did a good job highlighting the offending line of code, once I figured out what was happening. Personally, I think it would be great if there would be a way for the Loop component to automatically encode loop state into something like the page activation context and then automatically restore that point-in-time state when processing the eventlink request. It would work like a blend of the page activation context and the formState functionality already in the Loop component. However, this feature isn't really necessary as long as developers use the action context and avoid the gotcha that I ran into. -Nathan On Tue, Feb 16, 2010 at 10:45 PM, Kalle Korhonen kalle.o.korho...@gmail.com wrote: Nathan, since you invested considerable amount of time debugging a case that seems to be just a standard event bubbling behavior, do you think that there is anything you'd think the framework or somebody could do to make the logical error in your code more visible? I know Tapestry documentation has often been blamed and while everything is there, it's scattered - if you knew what you are looking for, you'd find it. But on the other side, I don't know how to make it better and I'm sure you can see now why the old-timers annoyingly enough just kept repeating the same message. So, is this just a case of having to learn the tricks of the trade or is there something we could collectively do to improve things? Kalle On Tue, Feb 16, 2010 at 7:18 PM, Nathan Kopp nathan0...@nathankopp.com wrote: For future reference... this in fact turned out to be a bug in my code. Under normal circumstances Tapestry will NOT attempt to perform parameter bindings when processing the EventLink. However, I accidentally left a line of code in my event handling method which referenced one of the parameters which was bound to the loop variable. The line of code was purely unnecessary, but it is what caused Tapestry to process the bindings, and thus trigger a null pointer exception. Once I removed that line of code, Tapestry was able to execute my method without any exceptions. Many thanks to those who offered the recommendations that eventually led me to locate my bug and resolve the problem. -Nathan On Tue, Feb 16, 2010 at 9:32 AM, Nathan Kopp nathan0...@nathankopp.com wrote: On
Re: Activation context for a component?
On Mon, Feb 15, 2010 at 3:21 PM, Thiago H. de Paula Figueiredo thiag...@gmail.com wrote: On Mon, 15 Feb 2010 03:51:08 -0200, Nathan Kopp nathan0...@nathankopp.com wrote: This looks like a bug in your code, most probably by working in a T4-ish way in T5. Well, it's certainly a bug in that I'm trying to do something that T5 doesn't seem to handle out-of-the-box. I disagree. A bug is something that doesn't work like it should. In this case, it could be the lack of a feature, not a bug. Or just lack of T5 experience. :) I have to laugh at the miscommunication happening here. Otherwise I'd get frustrated. I was not trying to say it was a bug in Tapestry. It's a bug in my code in the fact that I'm trying to use a nonexistent feature. And I'm NOT suggesting that T5 should replay loops like T4. Tapestry has moved beyond that and I have too. I am fully aware that Tapestry has introduced a number of other features (page activation context, action context, and formState) to take the place of replaying loops. I just haven't found the thing that handles this particular use case. It actually might be there but I just don't know. I do have a lack of T5 experience, as you point out. So I am asking to see if anyone on this forum can help me to discover what I'm missing. Please don't get defensive and think that I'm blaming T5. I really like T5. But I need to get my code to work. First, I need to rely on a loop variable. Period. The component exists in the context of one iteration of the loop. Without the loop variable, the component wouldn't need to exist. I didn't meant to remove the loop variable, just not using it when handling events. And how do you propose I do that? I'm NOT using the loop variable for handling events in my Java code. The NPE is happening not in my code but rather in the middle of T5's processing of the component tree and handling parameter bindings in preparation for triggering the event from th eventlink. I'm using the loop variable inside the TML file as part of passing a parameter to a component. There's no way around that, as far as I can see, though I am open to suggestions. I'll rephrase my problem like this: I need to rely on the loop variable, but it is null when tapestry processes the click from the eventlink, so I need to find a way to make it not null while tapestry processes that eventlink click... and specifically make it equal the a value for a specific iteration through the loop... the iteration that was occurring at the time the eventlink was being rendered. You'll won't have a nice solution for that because, in an event request, the loop is not rerendered, so the loop variable is not set. That's how T5 works. You need to find the solution in another way, most probably using the context of an EventLink. As stated before, the context for the eventlink doesn't seem to solve the problem. I already tried. My event method isn't even being reached, because the NPE happens in the middle of Tapestry's code (parameter binding) before Tapestry can get a chance to fire my event. I need to find a way to make the variable NOT NULL so that Tapestry is able to process all of the necessary parameter bindings so that it can fire my event... only then can I start thinking about the action context for the eventlink. 3) context for eventlink, actionlink, and form; #3 wont' work because my loop is not happening at the evenlink level, but rather at an intermediate level There's no such thing as an EventLink level. Events bubble from inside to outside. Just pass all the needed info in the context. Inside your component, create an event handler method for the event. Understood. That's what I meant to say... the level of the component into which the EventLink is placed... but that was really long so I wrote eventlink level instead. I already tried this suggestion and it didn't work. Trust me, please. I really did try all of these things with real code before saying that they didn't work. I'm not just assuming that they won't work... I actually really did try them all. :-) And don't forget that the EventLink context is independent from the page activation context. ComponentEventRequestParameters has two contexts: the page one (getPageActivationContext) and the event one (). Understood. That's why I mentioned both (#2 and #3) separately. I'm well aware that they are separate. Please don't misunderstand the tone here... I am extremely grateful for the desire to help me find a solution. I love the fact that Tapestry has a great community of users who are willing to give time to help. But I do know at least a bit of what I'm talking about. I'm not looking for an RTFM answer. I've already read the manuals. I've read some of the JavaDocs. I've read tutorials. I've even looked at Tapestry's internal source code. I understand the concepts of T5 and how they differ from T4. But none of that has yet helped me
Re: Activation context for a component?
For future reference... this in fact turned out to be a bug in my code. Under normal circumstances Tapestry will NOT attempt to perform parameter bindings when processing the EventLink. However, I accidentally left a line of code in my event handling method which referenced one of the parameters which was bound to the loop variable. The line of code was purely unnecessary, but it is what caused Tapestry to process the bindings, and thus trigger a null pointer exception. Once I removed that line of code, Tapestry was able to execute my method without any exceptions. Many thanks to those who offered the recommendations that eventually led me to locate my bug and resolve the problem. -Nathan On Tue, Feb 16, 2010 at 9:32 AM, Nathan Kopp nathan0...@nathankopp.comwrote: On Mon, Feb 15, 2010 at 3:21 PM, Thiago H. de Paula Figueiredo thiag...@gmail.com wrote: On Mon, 15 Feb 2010 03:51:08 -0200, Nathan Kopp nathan0...@nathankopp.com wrote: This looks like a bug in your code, most probably by working in a T4-ish way in T5. Well, it's certainly a bug in that I'm trying to do something that T5 doesn't seem to handle out-of-the-box. I disagree. A bug is something that doesn't work like it should. In this case, it could be the lack of a feature, not a bug. Or just lack of T5 experience. :) I have to laugh at the miscommunication happening here. Otherwise I'd get frustrated. I was not trying to say it was a bug in Tapestry. It's a bug in my code in the fact that I'm trying to use a nonexistent feature. And I'm NOT suggesting that T5 should replay loops like T4. Tapestry has moved beyond that and I have too. I am fully aware that Tapestry has introduced a number of other features (page activation context, action context, and formState) to take the place of replaying loops. I just haven't found the thing that handles this particular use case. It actually might be there but I just don't know. I do have a lack of T5 experience, as you point out. So I am asking to see if anyone on this forum can help me to discover what I'm missing.
Re: Activation context for a component?
Nathan, since you invested considerable amount of time debugging a case that seems to be just a standard event bubbling behavior, do you think that there is anything you'd think the framework or somebody could do to make the logical error in your code more visible? I know Tapestry documentation has often been blamed and while everything is there, it's scattered - if you knew what you are looking for, you'd find it. But on the other side, I don't know how to make it better and I'm sure you can see now why the old-timers annoyingly enough just kept repeating the same message. So, is this just a case of having to learn the tricks of the trade or is there something we could collectively do to improve things? Kalle On Tue, Feb 16, 2010 at 7:18 PM, Nathan Kopp nathan0...@nathankopp.com wrote: For future reference... this in fact turned out to be a bug in my code. Under normal circumstances Tapestry will NOT attempt to perform parameter bindings when processing the EventLink. However, I accidentally left a line of code in my event handling method which referenced one of the parameters which was bound to the loop variable. The line of code was purely unnecessary, but it is what caused Tapestry to process the bindings, and thus trigger a null pointer exception. Once I removed that line of code, Tapestry was able to execute my method without any exceptions. Many thanks to those who offered the recommendations that eventually led me to locate my bug and resolve the problem. -Nathan On Tue, Feb 16, 2010 at 9:32 AM, Nathan Kopp nathan0...@nathankopp.comwrote: On Mon, Feb 15, 2010 at 3:21 PM, Thiago H. de Paula Figueiredo thiag...@gmail.com wrote: On Mon, 15 Feb 2010 03:51:08 -0200, Nathan Kopp nathan0...@nathankopp.com wrote: This looks like a bug in your code, most probably by working in a T4-ish way in T5. Well, it's certainly a bug in that I'm trying to do something that T5 doesn't seem to handle out-of-the-box. I disagree. A bug is something that doesn't work like it should. In this case, it could be the lack of a feature, not a bug. Or just lack of T5 experience. :) I have to laugh at the miscommunication happening here. Otherwise I'd get frustrated. I was not trying to say it was a bug in Tapestry. It's a bug in my code in the fact that I'm trying to use a nonexistent feature. And I'm NOT suggesting that T5 should replay loops like T4. Tapestry has moved beyond that and I have too. I am fully aware that Tapestry has introduced a number of other features (page activation context, action context, and formState) to take the place of replaying loops. I just haven't found the thing that handles this particular use case. It actually might be there but I just don't know. I do have a lack of T5 experience, as you point out. So I am asking to see if anyone on this forum can help me to discover what I'm missing. - To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org For additional commands, e-mail: users-h...@tapestry.apache.org
Re: Activation context for a component?
Probably the tip I needed was this: When using an EventLink inside a loop, be sure that your event handling method does not refer to any loop variable either directly or indirectly. Especially be cautions of referring to parameters that may have been bound to any loop variable or a field of a loop variable. If you avoid referring to such parameters in the eventlink's event handler (and pass the information to that method using the context instead), Tapestry will not attempt to process the parameter binding, and therefore no problem will be caused by the null loop variable. I would have found this most easily if it were located in the primary documentation for either EventLink or Loop in the component reference. Tapestry's stack trace actually did a good job highlighting the offending line of code, once I figured out what was happening. Personally, I think it would be great if there would be a way for the Loop component to automatically encode loop state into something like the page activation context and then automatically restore that point-in-time state when processing the eventlink request. It would work like a blend of the page activation context and the formState functionality already in the Loop component. However, this feature isn't really necessary as long as developers use the action context and avoid the gotcha that I ran into. -Nathan On Tue, Feb 16, 2010 at 10:45 PM, Kalle Korhonen kalle.o.korho...@gmail.com wrote: Nathan, since you invested considerable amount of time debugging a case that seems to be just a standard event bubbling behavior, do you think that there is anything you'd think the framework or somebody could do to make the logical error in your code more visible? I know Tapestry documentation has often been blamed and while everything is there, it's scattered - if you knew what you are looking for, you'd find it. But on the other side, I don't know how to make it better and I'm sure you can see now why the old-timers annoyingly enough just kept repeating the same message. So, is this just a case of having to learn the tricks of the trade or is there something we could collectively do to improve things? Kalle On Tue, Feb 16, 2010 at 7:18 PM, Nathan Kopp nathan0...@nathankopp.com wrote: For future reference... this in fact turned out to be a bug in my code. Under normal circumstances Tapestry will NOT attempt to perform parameter bindings when processing the EventLink. However, I accidentally left a line of code in my event handling method which referenced one of the parameters which was bound to the loop variable. The line of code was purely unnecessary, but it is what caused Tapestry to process the bindings, and thus trigger a null pointer exception. Once I removed that line of code, Tapestry was able to execute my method without any exceptions. Many thanks to those who offered the recommendations that eventually led me to locate my bug and resolve the problem. -Nathan On Tue, Feb 16, 2010 at 9:32 AM, Nathan Kopp nathan0...@nathankopp.com wrote: On Mon, Feb 15, 2010 at 3:21 PM, Thiago H. de Paula Figueiredo thiag...@gmail.com wrote: On Mon, 15 Feb 2010 03:51:08 -0200, Nathan Kopp nathan0...@nathankopp.com wrote: This looks like a bug in your code, most probably by working in a T4-ish way in T5. Well, it's certainly a bug in that I'm trying to do something that T5 doesn't seem to handle out-of-the-box. I disagree. A bug is something that doesn't work like it should. In this case, it could be the lack of a feature, not a bug. Or just lack of T5 experience. :) I have to laugh at the miscommunication happening here. Otherwise I'd get frustrated. I was not trying to say it was a bug in Tapestry. It's a bug in my code in the fact that I'm trying to use a nonexistent feature. And I'm NOT suggesting that T5 should replay loops like T4. Tapestry has moved beyond that and I have too. I am fully aware that Tapestry has introduced a number of other features (page activation context, action context, and formState) to take the place of replaying loops. I just haven't found the thing that handles this particular use case. It actually might be there but I just don't know. I do have a lack of T5 experience, as you point out. So I am asking to see if anyone on this forum can help me to discover what I'm missing. - To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org For additional commands, e-mail: users-h...@tapestry.apache.org
Re: Activation context for a component?
I also think that you're over-complicating this. To me this sounds like a very normal use case, looping over items and creating a form for each one. It should just work. And it shouldn't be too many lines of complicated code either, so the code listed here confuses me a bit. Someone should post the rather simple code needed to do this. I don't have the time right now :) On Mon, Feb 15, 2010 at 12:06 AM, Thiago H. de Paula Figueiredo thiag...@gmail.com wrote: On Sun, 14 Feb 2010 17:33:43 -0200, Nathan Kopp nathan0...@nathankopp.com wrote: Even with your suggested change, this would still generate a null pointer exception (NPE) in the same place, since the problem lies with fooLoopVar being null when the eventlink is click is processed by Tapestry. You simply can't use it in the EventLink method handler. The NPE happens before I even get to rendering the description text field. Never forget that T5 uses redirect after post, so the event handling request is not the same as the render request. -- Thiago H. de Paula Figueiredo Independent Java, Apache Tapestry 5 and Hibernate consultant, developer, and instructor Owner, software architect and developer, Ars Machina Tecnologia da Informação Ltda. http://www.arsmachina.com.br - To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org For additional commands, e-mail: users-h...@tapestry.apache.org
Re: Activation context for a component?
On Sun, Feb 14, 2010 at 3:07 PM, Thiago H. de Paula Figueiredo thiag...@gmail.com wrote: On Sun, 14 Feb 2010 00:10:02 -0200, Nathan Kopp nathan.k...@gmail.com wrote: There are two things preventing this from working: First, Tapestry does not replay the loop when processing the eventlink (like it did in the 3.x and 4.x days). Therefore, fooLoopVar never gets changed from its default of null. Tapestry 5 doesn't have the rewind phase like previous versions had. And that's a very good thing, because it was quite complicated to understand and make it work. You should use the context parameter of EventLink and ActionLink to pass information to the event handler method. Understood. While I always liked the (poorly named) rewind phase, I do understand that lots of other people disliked it and I don't mind that it is gone. However, I'm trying to find an alternative method to achieve the same end goal (i.e. effective handling of highly dynamic custom components nested inside loops). I tried using the context parameter of the eventlink component, but since events start at the deepest level and bubble up, It starts at the EventLink instance level, not from the deepest one. That's what I meant by deepest level... sorry for not being clearer. However, in my case the NPE happens one layer deeper than the EventLink instance level. This means that the NPE happens BEFORE my event handler has a chance do anything with the context. T5 bails out with the NPE before it ever gets to the level containing the EventLink. I got the null pointerexception before I could use the context for anything useful at the outer (page) level. This looks like a bug in your code, most probably by working in a T4-ish way in T5. Well, it's certainly a bug in that I'm trying to do something that T5 doesn't seem to handle out-of-the-box. However, that doesn't change the fact that I need to achieve my end goal. I'm searching for the T5-style way of doing what I need to do. I'd like to stay in the box as much as possible, but I'm not afraid to step outside the box as long as the code is pretty. In Test.java, I added: String onPassivate() { return fooLoopVar==null?null:fooLoopVar.getName(); } You shouldn't rely in a variable used as a Loop object (in this case, fooLoopVar), as T5 doesn't have a rewind phase. First, I need to rely on a loop variable. Period. The component exists in the context of one iteration of the loop. Without the loop variable, the component wouldn't need to exist. I'll rephrase my problem like this: I need to rely on the loop variable, but it is null when tapestry processes the click from the eventlink, so I need to find a way to make it not null while tapestry processes that eventlink click... and specifically make it equal the a value for a specific iteration through the loop... the iteration that was occurring at the time the eventlink was being rendered. From what I understand, the page activation context (onPassivate/onActivate) IS one of the T5 ways of handling the loop variable in lieu of the rewind phase. In T5, you must encode the state in the next user input using the URL or hidden form fields. I know of three ways to do this: 1) and formState for a loop inside a form. 2) page activation context; 2) context for eventlink, actionlink, and form; #1 won't work for me because my loop is not enclosed in a form, and the action is an eventlink, not a form submission. #2 won't work because my loop is not happening at the page level, but rather at an intermediate level #3 wont' work because my loop is not happening at the evenlink level, but rather at an intermediate level Note: it might be possible to get the page activation context to work... but I need some way to communicate the info from the loop to the page activation context, and from the page activation context back to the loop. I might make a custom Loop component that is capable of storing its current state into the page activation context. I think I can use a ComponentResources to handle this. Basically, I need something that works like the page activation context, but generalized to work with any component at any level of the component tree. Inject ComponentEventLinkEncoder and use its decodePageRenderRequest(Request request) method (when rendering) or decodePageRenderRequest(Request request) (when handling an event). Both methods return an object that contains the page activation context. Hmmm... an interesting idea. I guess I could replace ComponentEventLinkEncoder with a custom implementation, but that sounds a little scary. I think I'll try the custom Loop component that stores state in the page activation context. Thanks for the idea of injecting something into my component, though... that spurred my idea of injecting ComponentResources so that my component can communicate with the underlying page to store state in the activation context. :) I hope this is starting
Re: Activation context for a component?
I agree... It sounded like a normal use case to me and I was fully expecting it to just work. But it didn't. I'm not trying to complicate things... I'm looking for an uncomplicated solution... but I have not found one yet. All of the code necessary to run this example can be found in my original email except for the backing-bean for the Test page and some boilerplate code (XML headers, Java getters/setters, and imports). Below is the Java code for the Test page without the onPassivate/onActivate methods. This isn't pseudo-code... all of this is the real code that I created for myself to isolate the issue that I'm facing. I tried to boil the use case down to its simplest form to make sure nothing else was happening behind the scenes to break it. Here's the backing-bean for the Test.tml page: public class Test { @Property private Foo fooLoopVar; // this static list takes the place of an injected JPA DAO private static ListFoo list = new ArrayListFoo(); static { list.add(new Foo(foo1, new Donkey(donkey1,This is Donkey 1))); list.add(new Foo(foo2, new Donkey(donkey2,This is Donkey 2))); list.add(new Foo(foo3, new Donkey(donkey3,This is Donkey 3))); } public Foo getFirstFoo() { return getFooList().get(0); } public Foo getSecondFoo() { return getFooList().get(1); } public Foo getThirdFoo() { return getFooList().get(2); } public ListFoo getFooList() { return list; } } If you take this code combined with the code in the original email, you have all you need to demonstrate the null pointer exception. Add the onPassivate/onActivate methods to make the NPE go away... but remember that this solution doesn't work if Test is used as a component instead of a page. To summarize the code: Two simple Java Beans : Foo and Donkey; Donkey contains string name and string descr; Foo contains string name and a reference to a Donkey. One component that takes a Donkey as a parameter, displays the Donkey, and contains an embedded editing form that can be turned on and off using eventlinks internal to the component. One page, containing a list of Foo objects, each containing a Donkey object. It uses the custom component to render (with editing capability) each Donkey in the list. -Nathan On Mon, Feb 15, 2010 at 3:01 AM, Inge Solvoll inge.tapes...@gmail.comwrote: I also think that you're over-complicating this. To me this sounds like a very normal use case, looping over items and creating a form for each one. It should just work. And it shouldn't be too many lines of complicated code either, so the code listed here confuses me a bit. Someone should post the rather simple code needed to do this. I don't have the time right now :) On Mon, Feb 15, 2010 at 12:06 AM, Thiago H. de Paula Figueiredo thiag...@gmail.com wrote: On Sun, 14 Feb 2010 17:33:43 -0200, Nathan Kopp nathan0...@nathankopp.com wrote: Even with your suggested change, this would still generate a null pointer exception (NPE) in the same place, since the problem lies with fooLoopVar being null when the eventlink is click is processed by Tapestry. You simply can't use it in the EventLink method handler. The NPE happens before I even get to rendering the description text field. Never forget that T5 uses redirect after post, so the event handling request is not the same as the render request. -- Thiago H. de Paula Figueiredo Independent Java, Apache Tapestry 5 and Hibernate consultant, developer, and instructor Owner, software architect and developer, Ars Machina Tecnologia da Informação Ltda. http://www.arsmachina.com.br - To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org For additional commands, e-mail: users-h...@tapestry.apache.org
Re: Activation context for a component?
On Mon, 15 Feb 2010 03:51:08 -0200, Nathan Kopp nathan0...@nathankopp.com wrote: This looks like a bug in your code, most probably by working in a T4-ish way in T5. Well, it's certainly a bug in that I'm trying to do something that T5 doesn't seem to handle out-of-the-box. I disagree. A bug is something that doesn't work like it should. In this case, it could be the lack of a feature, not a bug. Or just lack of T5 experience. :) First, I need to rely on a loop variable. Period. The component exists in the context of one iteration of the loop. Without the loop variable, the component wouldn't need to exist. I didn't meant to remove the loop variable, just not using it when handling events. I'll rephrase my problem like this: I need to rely on the loop variable, but it is null when tapestry processes the click from the eventlink, so I need to find a way to make it not null while tapestry processes that eventlink click... and specifically make it equal the a value for a specific iteration through the loop... the iteration that was occurring at the time the eventlink was being rendered. You'll won't have a nice solution for that because, in an event request, the loop is not rerendered, so the loop variable is not set. That's how T5 works. You need to find the solution in another way, most probably using the context of an EventLink. 3) context for eventlink, actionlink, and form; #3 wont' work because my loop is not happening at the evenlink level, but rather at an intermediate level There's no such thing as an EventLink level. Events bubble from inside to outside. Just pass all the needed info in the context. Inside your component, create an event handler method for the event. And don't forget that the EventLink context is independent from the page activation context. ComponentEventRequestParameters has two contexts: the page one (getPageActivationContext) and the event one (). -- Thiago H. de Paula Figueiredo Independent Java, Apache Tapestry 5 and Hibernate consultant, developer, and instructor Owner, software architect and developer, Ars Machina Tecnologia da Informação Ltda. http://www.arsmachina.com.br - To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org For additional commands, e-mail: users-h...@tapestry.apache.org
Activation context for a component?
Hey everyone! I'm new here and I apologize for not lurking long before posting. I have searched the archives extensively for this issue and have come up empty, so I'm just going to jump in. I'm working in Tapestry 5.1.0.5 (the latest as far as I know) and I've run into a use-case that I can't figure out how to solve cleanly with T5. I actually used Tapestry extensively back in the 3.x and 4.x days, partially because it could solve this particular use case very well when other frameworks would fall flat. Unfortunately, Tapestry works differently now, so I think I need some help solving this in the new paradigm. Also, this is really long, because I wanted to include lots of code to give really good context to my question. Here goes: I have two objects, let's call them Foo and Donkey (shout-out to the Java Posse). Each Foo object contains a Donkey object, like this: public class Donkey { private String name; private String descr; // constructor getters/setters go here } public class Foo { private String name; private Donkey donkey; // constructor getters/setters go here } Now... the Donkey object represents user-contributed content. Anywhere on my site where I display a Donkey, I want to let the user edit the instance. To do this, I've created a reusable custom component that displays the Donkey, including inline editing capabilities. It's rudimentary now, but eventually it'll probably use an Ajax modal popup from ChenilleKit. ==ViewDonkeyInlineEdit.tml=== !DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Strict//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd; t:container xmlns:t=http://tapestry.apache.org/schema/tapestry_5_1_0.xsd; xmlns:p=tapestry:parameter Donkey's name: ${donkey.name}br/ t:if test=editing t:form t:errors/ Description: t:textfield value=editDonkey.descr size=50/ t:submit value=Save event=saveEditDonkey/ t:eventlink event=cancelEditDonkeyCancel/t:eventlinkbr/ /t:form p:else Description: ${donkey.descr} t:eventlink event=startEditDonkeyEdit/t:eventlinkbr/ /p:else /t:if /t:container ViewDonkeyInlineEdit.java= public class ViewDonkeyInlineEdit { @Property @Parameter private Donkey donkey; @Persist @Property private Donkey editDonkey; public boolean isEditing() { return (editDonkey!=null editDonkey.getName().equals(donkey.getName())); } public void onStartEditDonkey() { editDonkey = new Donkey(donkey.getName(), donkey.getDescr()); } public void onSaveEditDonkey() { donkey.setDescr(editDonkey.getDescr()); editDonkey = null; } public void onCancelEditDonkey() { editDonkey = null; } } == Now, let's use it in a page: Test.tml == html xmlns:t=http://tapestry.apache.org/schema/tapestry_5_1_0.xsd; xmlns:p=tapestry:parameter Here's a foo: ${firstFoo.name}br/ t:viewDonkeyInlineEdit donkey=firstFoo.donkey/br/br/ Here's a foo: ${secondFoo.name}br/ t:viewDonkeyInlineEdit donkey=secondFoo.donkey/br/br/ Here's a foo: ${thirdFoo.name}br/ t:viewDonkeyInlineEdit donkey=thirdFoo.donkey/br/ /html = This works great. No problems. Clearly, though, this is *screaming* to be put into a loop. So, let's try this: === Test.tml (version 2) = html xmlns:t=http://tapestry.apache.org/schema/tapestry_5_1_0.xsd; xmlns:p=tapestry:parameter t:loop source=fooList value=fooLoopVar Here's a foo: ${fooLoopVar.name}br/ t:viewDonkeyInlineEdit donkey=fooLoopVar.donkey/br/br/ /t:loop /html == Of course, this doesn't work. (If it did work, I wouldn't be writing this message right now.) When I click the edit link to triggger the startDonkeyEdit event, I get a null pointer exception. There are two things preventing this from working: First, Tapestry does not replay the loop when processing the eventlink (like it did in the 3.x and 4.x days). Therefore, fooLoopVar never gets changed from its default of null. Second, there's only one instance of the ViewDonkeyInlineEdit component inside the loop. All of the eventlink URLs look identical, so there's no way to tell which Donkey should be edited. I tried using the context parameter of the eventlink component, but since events start at the deepest level and bubble up, I got the null pointer exception before I could use the context for anything useful at the outer (page) level. Next, I tried adding an activation context to the page. In Test.java, I added: String onPassivate() { return fooLoopVar==null?null:fooLoopVar.getName(); } public void onActivate(String fooName) { for(Foo foo : list) { if(foo.getName().equals(fooName)) { this.fooLoopVar = foo; } } } This worked really well. It appears
Re: Activation context for a component?
Hi Nathan, Anywhere on my site where I display a Donkey, I want to let the user edit the instance. So then do exactly that... Tapestry 5 is sometimes simpler than you might expect, to me it seems you are complicating things unnecessarily... why are you creating new instances when editing? You shouldn't need to, simply pass in foo and call getDonkey and edit that instance. Your loop should just work, simply bind foo and the correct instance will always be bound, with a new instance of the inlinedit component for every iteration, so you have no need for extended context info in this case. t:loop source=fooList value=fooLoopVar Here's a foo: ${fooLoopVar.name}br/ t:viewDonkeyInlineEdit foo=fooLoopVar/br/br/ /t:loop public class ViewDonkeyInlineEdit { @Parameter (allownull=false, required=true) @Property private Foo foo; //wired to your event onEdit etc. @Persist @Property private Boolean isEditing; public void onSaveEditDonkey() { foo.getDonkey().saveToDB(); } } Description: t:textfield value=foo.donkey.descr size=50/ Its that simple. Peter - Original Message - From: Nathan Kopp nathan.k...@gmail.com To: users@tapestry.apache.org Sent: Sunday, 14 February, 2010 04:10:02 GMT +02:00 Athens, Beirut, Bucharest, Istanbul Subject: Activation context for a component? Hey everyone! I'm new here and I apologize for not lurking long before posting. I have searched the archives extensively for this issue and have come up empty, so I'm just going to jump in. I'm working in Tapestry 5.1.0.5 (the latest as far as I know) and I've run into a use-case that I can't figure out how to solve cleanly with T5. I actually used Tapestry extensively back in the 3.x and 4.x days, partially because it could solve this particular use case very well when other frameworks would fall flat. Unfortunately, Tapestry works differently now, so I think I need some help solving this in the new paradigm. Also, this is really long, because I wanted to include lots of code to give really good context to my question. Here goes: I have two objects, let's call them Foo and Donkey (shout-out to the Java Posse). Each Foo object contains a Donkey object, like this: public class Donkey { private String name; private String descr; // constructor getters/setters go here } public class Foo { private String name; private Donkey donkey; // constructor getters/setters go here } Now... the Donkey object represents user-contributed content. Anywhere on my site where I display a Donkey, I want to let the user edit the instance. To do this, I've created a reusable custom component that displays the Donkey, including inline editing capabilities. It's rudimentary now, but eventually it'll probably use an Ajax modal popup from ChenilleKit. ==ViewDonkeyInlineEdit.tml=== !DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Strict//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd; t:container xmlns:t=http://tapestry.apache.org/schema/tapestry_5_1_0.xsd; xmlns:p=tapestry:parameter Donkey's name: ${donkey.name}br/ t:if test=editing t:form t:errors/ Description: t:textfield value=editDonkey.descr size=50/ t:submit value=Save event=saveEditDonkey/ t:eventlink event=cancelEditDonkeyCancel/t:eventlinkbr/ /t:form p:else Description: ${donkey.descr} t:eventlink event=startEditDonkeyEdit/t:eventlinkbr/ /p:else /t:if /t:container ViewDonkeyInlineEdit.java= public class ViewDonkeyInlineEdit { @Property @Parameter private Donkey donkey; @Persist @Property private Donkey editDonkey; public boolean isEditing() { return (editDonkey!=null editDonkey.getName().equals(donkey.getName())); } public void onStartEditDonkey() { editDonkey = new Donkey(donkey.getName(), donkey.getDescr()); } public void onSaveEditDonkey() { donkey.setDescr(editDonkey.getDescr()); editDonkey = null; } public void onCancelEditDonkey() { editDonkey = null; } } == Now, let's use it in a page: Test.tml == html xmlns:t=http://tapestry.apache.org/schema/tapestry_5_1_0.xsd; xmlns:p=tapestry:parameter Here's a foo: ${firstFoo.name}br/ t:viewDonkeyInlineEdit donkey=firstFoo.donkey/br/br/ Here's a foo: ${secondFoo.name}br/ t:viewDonkeyInlineEdit donkey=secondFoo.donkey/br/br/ Here's a foo: ${thirdFoo.name}br/ t:viewDonkeyInlineEdit donkey=thirdFoo.donkey/br/ /html = This works great. No problems. Clearly, though, this is *screaming* to be put into a loop. So, let's try this: === Test.tml (version 2) = html xmlns:t=http://tapestry.apache.org/schema/tapestry_5_1_0.xsd; xmlns:p=tapestry:parameter t:loop source=fooList value=fooLoopVar
Re: Activation context for a component?
Hi! On Sun, 14 Feb 2010 00:10:02 -0200, Nathan Kopp nathan.k...@gmail.com wrote: There are two things preventing this from working: First, Tapestry does not replay the loop when processing the eventlink (like it did in the 3.x and 4.x days). Therefore, fooLoopVar never gets changed from its default of null. Tapestry 5 doesn't have the rewind phase like previous versions had. And that's a very good thing, because it was quite complicated to understand and make it work. You should use the context parameter of EventLink and ActionLink to pass information to the event handler method. Second, there's only one instance of the ViewDonkeyInlineEdit component inside the loop. Yes. Less memory usage! The solution is the same as above. All of the eventlink URLs look identical, so there's no way to tell which Donkey should be edited. See above. I tried using the context parameter of the eventlink component, but since events start at the deepest level and bubble up, It starts at the EventLink instance level, not from the deepest one. I got the null pointerexception before I could use the context for anything useful at the outer (page) level. This looks like a bug in your code, most probably by working in a T4-ish way in T5. In Test.java, I added: String onPassivate() { return fooLoopVar==null?null:fooLoopVar.getName(); } You shouldn't rely in a variable used as a Loop object (in this case, fooLoopVar), as T5 doesn't have a rewind phase. Basically, I need something that works like the page activation context, but generalized to work with any component at any level of the component tree. Inject ComponentEventLinkEncoder and use its decodePageRenderRequest(Request request) method (when rendering) or decodePageRenderRequest(Request request) (when handling an event). Both methods return an object that contains the page activation context. -- Thiago H. de Paula Figueiredo Independent Java, Apache Tapestry 5 and Hibernate consultant, developer, and instructor Owner, software architect and developer, Ars Machina Tecnologia da Informação Ltda. http://www.arsmachina.com.br - To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org For additional commands, e-mail: users-h...@tapestry.apache.org
Re: Activation context for a component?
Good thought, but the copy of Donkey isn't the problem. (Actually, when using Hibernate or JPA, you'd want to make a copy to allow cancel to work, because altering a JPA entity by binding directly to the real instance could cause the database to be updated immediately... JPA/Hibernate doesn't wait for you to call any saveToDb or persist method.) Note that my instance used for editing has the @Persist annotation, so Tapestry does a great job remembering its state. Even with your suggested change, this would still generate a null pointer exception (NPE) in the same place, since the problem lies with fooLoopVar being null when the eventlink is click is processed by Tapestry. The NPE happens before I even get to rendering the description text field. -Nathan On Sun, Feb 14, 2010 at 2:02 PM, p.stavrini...@albourne.com wrote: Hi Nathan, Anywhere on my site where I display a Donkey, I want to let the user edit the instance. So then do exactly that... Tapestry 5 is sometimes simpler than you might expect, to me it seems you are complicating things unnecessarily... why are you creating new instances when editing? You shouldn't need to, simply pass in foo and call getDonkey and edit that instance. Your loop should just work, simply bind foo and the correct instance will always be bound, with a new instance of the inlinedit component for every iteration, so you have no need for extended context info in this case. t:loop source=fooList value=fooLoopVar Here's a foo: ${fooLoopVar.name}br/ t:viewDonkeyInlineEdit foo=fooLoopVar/br/br/ /t:loop public class ViewDonkeyInlineEdit { @Parameter (allownull=false, required=true) @Property private Foo foo; //wired to your event onEdit etc. @Persist @Property private Boolean isEditing; public void onSaveEditDonkey() { foo.getDonkey().saveToDB(); } } Description: t:textfield value=foo.donkey.descr size=50/ Its that simple. Peter - Original Message - From: Nathan Kopp nathan.k...@gmail.com To: users@tapestry.apache.org Sent: Sunday, 14 February, 2010 04:10:02 GMT +02:00 Athens, Beirut, Bucharest, Istanbul Subject: Activation context for a component? Hey everyone! I'm new here and I apologize for not lurking long before posting. I have searched the archives extensively for this issue and have come up empty, so I'm just going to jump in. [clip]
Re: Activation context for a component?
On Sun, 14 Feb 2010 17:33:43 -0200, Nathan Kopp nathan0...@nathankopp.com wrote: Even with your suggested change, this would still generate a null pointer exception (NPE) in the same place, since the problem lies with fooLoopVar being null when the eventlink is click is processed by Tapestry. You simply can't use it in the EventLink method handler. The NPE happens before I even get to rendering the description text field. Never forget that T5 uses redirect after post, so the event handling request is not the same as the render request. -- Thiago H. de Paula Figueiredo Independent Java, Apache Tapestry 5 and Hibernate consultant, developer, and instructor Owner, software architect and developer, Ars Machina Tecnologia da Informação Ltda. http://www.arsmachina.com.br - To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org For additional commands, e-mail: users-h...@tapestry.apache.org