3

I have 3 listboxes: the first with types, the second with subtypes of the chosen type and the third with elements of the chosen type and subtype.

<p:selectonelistbox id = "types" rendered = "true" valuechangelistener = "#{bean.selectType}" onchange = "submit()" />
<p:selectonelistbox id = "subtypes" rendered = "#{bean.subtypesFlag}" valuechangelistener = "#{bean.selectSubType}" onchange = "submit()" />
<p:selectonelistbox id = "elements" rendered = "#{bean.elementsFlag}" />


@viewscoped
...
private Boolean subtypesFlag = false;
private Boolean elementsFlag = false;
public void selectType(ValueChangeEvent  event) {
  subtypesFlag = true;
  elementsFlag = false;
}
public void selectSubType(ValueChangeEvent  event) {
  elementsFlag = true;
}

The first listbox is always displayed, the second only when some type is selected, the third only when subtype is selected.

When I open the view only types are rendered. Then I press some type, subtypes become visible. Next I press some subtype, elements become visible. Everything is working fine.

But when I select another type, I want to show only subtypes, but no elements listbox. And there I have a problem. When I really select another type, I get all three listboxes visible. When I press again another type once more I see only types and subtypes, no elements listbox.

That seems to be an interesting fact, when on apply request values phase your component has rendered flag set to false and it becomes true during validate phase (when value action listeners are invoked) it changes its rendered state and IS rendered on render response phase. But when its rendered flag is true on apply request values phase and gets to false on validate phase it doesn't see the change and is STILL rendered on render response phase.

Can I change its state to false somehow (programmatically maybe or invalidate its rendered flag) on validate phase?

Mojarra 2.2.4, Primefaces 4, Glassfish 4.

Skycelot
  • 33
  • 5

1 Answers1

5

valueChangeListener is the wrong tool for the concrete functional requirement of executing a method during the invoke application phase (as you clearly intented). It's indeed executed during the validations phase (as you discovered). You need <f:ajax listener> instead. Perhaps you were focusing too much on JSF 1.x flavored examples while you're actually using JSF 2.x.

Fix it accordingly:

<p:selectOneListbox id="types">
    <p:ajax listener="#{bean.selectType}" update="@form" />
</p:selectOneListbox>
<p:selectOneListbox id="subtypes" rendered="#{bean.subtypesFlag}">
    <p:ajax listener="#{bean.selectSubType}" update="@form" />
</p:selectOneListbox>
<p:selectOneListbox id="elements" rendered="#{bean.elementsFlag}" />

Don't forget to remove the ValueChangeEvent argument from the methods.

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Deleted my answer as yours is the correct one. As usual. Keep up the good work. – Andre Dec 07 '13 at 13:10
  • 1
    @Andre: If you want to be as good as me, try to recreate OP's problem in your sandbox environment, really solve the problem locally and test the code before posting as answer. You'll also actually learn something and become really good. I did this 10 years ago. – BalusC Dec 07 '13 at 13:11
  • I normally do this, actually. This was a simple one and I thought I could get away with being lazy. My bad. Besides, if I were to try it first, you would have beaten me to it... LOL. On another note, wouldn't it make sense to wrap the components with a panel and update only those components instead of updating the whole form? – Andre Dec 07 '13 at 13:14
  • @Andre: would indeed also prefer that, but OP's current approach already updates the whole page, so updating the form wouldn't harm. It's up to the OP to finetune that further. – BalusC Dec 07 '13 at 13:15
  • BalusC, I hoped you would answer and it's happened :) it's working perfect now! I'm really afraid of ajax, but maybe this case will make it simpler for me :) – Skycelot Dec 07 '13 at 13:37