3

I encounter this issue when I am trying to update a zone of a component in a handled event (onValueChanged of a select box).

[ERROR] TapestryModule.RequestExceptionHandler Processing of request failed with uncaught exception: Failure writing parameter 'value' of component calendar/Stereotype:daycomponent.selectcategoryactivity: Property 'day' (within property expression 'day.category', of com.hb.craproject.web.components.calendar.stereotype.AddDayStereotypeComponent@3a6b9a8a) is null.
org.apache.tapestry5.ioc.internal.OperationException: Failure writing parameter 'value' of component calendar/Stereotype:daycomponent.selectcategoryactivity: Property 'day' (within property expression 'day.category', of com.hb.craproject.web.components.calendar.stereotype.AddDayStereotypeComponent@3a6b9a8a) is null. [at classpath:com/hb/craproject/web/components/calendar/stereotype/AddDayStereotypeComponent.tml, line 24]

"Day" is a parameter defined like this :

@Parameter(required=true)
@Property
private DayStereotypeBean day

And when the component is rendering for the first time, all works fine. It's only when I try to change the selected value that it crashes and given that error message.

My DayComponents are declared like this in my tml page :

<t:loop source="week" value="dayBean">
  <tr style="border :0.1em solid blue; border-radius : 0.5em">
    <t:day t:id="dayComponent" day="dayBean" /></tr></t:loop>

So this is a List of Day beans. This list is feeded in the setuprender event handler of the page.

I don't understand why the Day parameter lost his reference in the event handler of the select component :

public Object onValueChangedFromSelectDuree(String duree)
{    
//throwing exception, day.Day is a String, this line is just for showing you that the object doesn't exist anymore in the method, if this line is not here, the exception is throwed too because my select tml component use (like many oher components) that object
    day.getDay(); 
    return request.isXHR() ? zoneDuree.getBody() : null;
}

And now you can see the select tml component :

<t:zone t:id="zoneDuree">
        <t:select t:id="selectDuree"
            model="literal:journée,demi-journée,définir" value="day.duree"  zone="zoneDuree" /> <!-- here some fields depending of the select value --></t:zone>

Any idea should be appreciated.

(sorry for my bad english ;) )

Gadou
  • 49
  • 1
  • 7

1 Answers1

3

The "setuprender" event only fires when your page is initially rendered. Anything initialized in setupRender() will be null in the subsequent event requests.

Here's a few options:

  1. Use the context of the event to pass all the required contextual information. You'll need to initialize any @Parameters needed by your ajax block in the event before the template renders.
  2. Initialize your fields in onActivate() instead of setupRender() as onActivate() is fired before page render AND before event handlers
  3. Use @Persist to persist values in the HTTPSession between requests. I personally hate this approach and avoid HTTPSession usage at all costs.

You might find that the builtin select / ajax update is not sufficient since you can't provide multiple context values. Take a look at the onEvent mixin here which allows you to customise what gets passed from the client to the serverside event when a clientside event (eg change) occurs.

lance-java
  • 25,497
  • 4
  • 59
  • 101
  • Thank you for your answer ! I've seen your onEvent mixin. It is clear and tricky but it will be heavy to set all values I got in my Day beans. I think I must use a persist method. Can you tell me why do you hate and avoid this approach ? And I thought that Parameter annotation did an implicite Persist annotation ? That's why I don't know why the parameter is lost after each request ? Otherwise, can I use a bean object as context sent to the onEvent mixin ? – Gadou Oct 14 '13 at 14:47
  • As long as you have a ValueEncoder registered for your bean's class, you can use it as context. Using the HTTPSession does not scale well since you need to maintain serverside state for each client. You also get issues when the user opens two browser windows for different values. Session usage sometimes requires 'messy' code to clear the session (ie when the user comes back to a page twice). Using the URL (ie event context) means that your app can be stateless and can easily support multiple browser windows. It keeps your app simple and scalable too. – lance-java Oct 14 '13 at 14:59
  • Well the persist method works well but I will make it with a ValueEncoder and try with your better way. Thank you for your answer, I will post here your solution when it will be done ;-) (this evening or tomorrow) – Gadou Oct 14 '13 at 16:17
  • You will laugh at me... I don't know what is the better way for encoding my bean class... The only ValueEncoders I did were really simple (an unique value I had to find in my database) but, here I have many volatile datas and I can't identify my bean by an unique ID so I must build a better encoder like SOAP does in xml or other. Should I know something for doing the ValueEncoder the best possible ? An other small question : Where should I define the value encoder of a bean ? – Gadou Oct 15 '13 at 08:18
  • How do you get the values in the first place? Are you sure you can't look them up again given some parameter? For a one-off ValueEncoder you might use tapestry's [JSON](http://tapestry.apache.org/tapestry5/apidocs//org/apache/tapestry5/json/JSONObject.html) implementation. For a more enterprise solution you'd probably use something like JAXB to serialize to JSON (or XML). Config for ValueEncoder is in the [javadoc](http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ValueEncoder.html) – lance-java Oct 15 '13 at 08:53
  • Your demo and the ZoneUpdater mixin from jumpstart are really great ! I will learn more about it and use this way. (I have lot of things to learn, I am newbie with tapestry and j2ee...) Thank you, this is really very helpful for many things :-). – Gadou Oct 15 '13 at 11:53
  • Hello, I don't know if I would post a new ask question for this below: I used the mixin for send the context but I can't use the ValueEncoder for my select component. Before the mixin, It worked well but now it always throws me an exception because String cannont be cast to my bean type. Seems like it doesn't use the valueencoder to parse my string to my bean. Should I post a new ask ? Thanks – Gadou Oct 18 '13 at 12:39
  • It's probably best to ask a new SO question. I'd need to see your serverside event. I'm guessing your casting string to bean instead of declaring bean as the event are type. – lance-java Oct 19 '13 at 09:36