1

I'm using a omnifaces o:tree of "branches" where each branch has a "list of leafs" with the attribute "color" which should be editable in the tree.

- branch 0
  - leaf 0 (color = "green")
  - leaf 1 (color = "yellow")
- branch 1
  - leaf 0 (color = "purple")
  - branch 1_0
    - leaf 1 (color = "red")
    - leaf 2 (color = "orange")
    - leaf 3 (color = "brown")

Adding/removing branches and adding leafs to any branch works fine and as expected. Also the rendering of any complex tree including all the list of leafes (displaying of the color attribute with the correct value) works like a charme.

But changing the color or removing a leaf (so whatever is within the ui:repeat) only works as expected for the last rendered branch.

The "color" input fields for the other leafes/branches don't work at all and the delete leaf link within the ui:repeat also doesn't work as for the leaf attribute in removeLeaf(...) always the corresponding leaf from the last rendered branch gets passed. So in the above example clicking on delete for the yellow leaf from branch 0 will call removeLeaf(orange, branch 0) which will then oviously not delete anything as branch 0 has no orange leaf.

This is the code strapped down to the essential part - anything else can be provided if needed:

<h:form>
  <o:tree value="#{treeBean.tree}" var="branchEntity" varNode="branchNode">
    <o:treeNode>
      <o:treeNodeItem>
        <ui:repeat value="#{branchEntity.leafList}" var="leaf">
          <h:panelGrid columns="2">     
            <p:inputText value="#{leaf.color}" />   
            <p:commandLink action="#{treeBean.removeLeaf(leaf, branchEntity)}" styleClass="ui-icon ui-icon-trash"
                        process="@form" update="@form" />               
          </h:panelGrid>
        </ui:repeat>    

        <p:commandLink action="#{treeBean.addLeaf(branchEntity)}" styleClass="ui-icon ui-icon-plus"
                process="@form" update="@form" />
        <o:treeInsertChildren />
      </o:treeNodeItem>
    </o:treeNode>
  </o:tree>
  <p:commandButton id="save" value="Save" action="#{treeBean.save}" process="@form" update="@form" />
</h:form>

I know that there is some issue with nested ui:repeat but as I'm on Mojarra 2.1.19 I guess it's not the case here. And actually nesting two ui:repeats works fine if I replace o:tree by a ui:repeat which iterates over a list of branches. But then I obviously lost the tree functionality which I need. This I just tested to verify nested ui:repeats work properly.

This problem seems to be similar to another question but it's not exactly the same...

If I replace the the inner ui:repeat by a p:dataList (as suggested in some other answers to solve ui:repeat problems and also now in BalusC answer here) the removeLeaf() links will all work proper but still only color input fields of the last branch will be bound.

UPDATE: I now had a closer look when using the p:dataList. The POST content from the AJAX request which I got from my browsers developer tools looks good:

javax.faces.partial.ajax=true
javax.faces.source=hForm:save
javax.faces.partial.execute=hForm
javax.faces.partial.render=hForm
hForm:save=hForm:save
hForm=hForm
hForm:oTree:0:pDataList:0:color=green
hForm:oTree:0:pDataList:1:color=yellow
hForm:oTree:1:pDataList:0:color=purple
hForm:oTree:1_0:pDataList:0:color=red
hForm:oTree:1_0:pDataList:1:color=orange
hForm:oTree:1_0:pDataList:2:color=brown
javax.faces.ViewState=-6137230173999059936:-6718691551411872927

The treeBean.save() method is just logging the whole Tree.toString() to console which ends up like this:

[Branch [leafList=[Leaf [color=null], Leaf [color=null]]],
Branch [leafList=[Leaf [color=null]]]
[Branch [leafList=[Leaf [color=red], Leaf [color=orange], Leaf [color=brown]]]]]

If the color had some value != null before, the value remains the same - so it doesn't get overriden by null. I'm not yet deep enough into JSF to really know how to investigate where the information gets lost on it's way.

(I initially used Mojarra 2.1.19 on JBoss EAP 6.2 + Primefaces 5.2 + Omnifaces 2.1 but also experience exactly the same on Mojarra 2.2.12, TomEE, Primefaces 5.3 + Omnifaces 2.2. The complete Maven Eclipse sample project can be found here I added even one more simple String attribute (no List) directly to the Branch which works fine.)

Community
  • 1
  • 1
Ralf
  • 569
  • 4
  • 14

1 Answers1

1

This is indeed caused by a state management bug in <ui:repeat>. It didn't properly recognize itself being nested in another iterator and stubbornly clears out the state before being revisited during each iteration of the parent iterator. It only recognizes a parent UIRepeat or UIData, but that's it. The <o:tree> doesn't and can't extend from UIData, and the UIRepeat is unfortunately a implementation-specific class and thus can't be used publicly as long as you want to be independent from a specific JSF implementation (Mojarra, MyFaces, etc).

Your best bet is to replace <ui:repeat> by a real UIData component which has a much better state management implementation. I just tried it here and adding items works just fine for me with <h:dataTable> and <p:dataList>. Only removing items failed with <h:dataTable>, because it rendered wrong client IDs. It's not taking into account the container client ID. The <p:dataList> worked for me in both cases of adding and removing items. Still updating the server side model of any bound input fields in the list fails as discussed in detail in the comments of this answer.

Replacing the entire <ui:repeat> by a <p:dataList type="none"> (without type, it will render an <ul><li>) is the closest you can get.

<p:dataList type="none" value="#{branchEntity.leafList}" var="leaf">
    ...
</p:dataList>

World would have been much simpler if JSF offered a public UIRepeat-like (marker) interface which all those repeaters could just check for when they're about to manage the state.

Ralf
  • 569
  • 4
  • 14
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • So you filed a jsf 2.4 enhancement? ;-) Or can either you or Arjen slip it in 2.3 in a sneaky way? ;-) – Kukeltje Dec 08 '15 at 16:01
  • It's definitely in our 2.3 wish list. – BalusC Dec 08 '15 at 16:13
  • Thx for the quick answer. But actually it does not work for me. With `h:dataTable` things start to get really crazy for me. The removeLeaf link for example gets called n-times and deletes ALL the (1st) leaves from any branches. If I look into the generated html the id for the deleteLeaf link looks like `hForm:oTree:hDataTable:0:removeLeaf`. The same id generated when i use `p:dataList` instead looks like `hForm:oTree:1_0:pDataList:0:removeLeaf`and works fine. But then still the inputText is not working. `ui:repeat`, `h:dataTable`, `p:dataList` behave all differently but non as I want them to. – Ralf Dec 08 '15 at 16:24
  • Indeed, `` worked with adding items, but failed with removing items. However, `` behaved correctly for me. I will update the answer. How exactly does the inputText fail for you? I used Mojarra 2.2.12 + PrimeFaces 5.3. – BalusC Dec 09 '15 at 09:10
  • In my case using `p:dataList` all adding/removing branches/leaves works fine but only the last list of rendered input fields get bound - so in the above example the input fields red, orange, brown work - changes in the other input fields don't reflect back in the model. If I remove branch 1_0 the "purple" input field would then work. Sadly I don't have the time to investigate further on this right now. Maybe it's also a version issue. (Mojarra 2.1.19 + Primefaces 5.2 + Omnifaces 2.1) It would be great if there was a easy way to host small JSF examples in a JSFiddle style... – Ralf Dec 10 '15 at 08:50
  • I added some more information in the end of the original question to what happens in my case using p:dataList. – Ralf Dec 11 '15 at 08:10
  • Set `javax.faces.SERIALIZE_SERVER_STATE` to `true` in `web.xml`, or upgrade to latest 2.2 as per instructions in http://stackoverflow.com/q/17085717 – BalusC Dec 11 '15 at 08:51
  • I tried both. No success. I also tried the old parameter name for 2.1 as of your [post](http://balusc.omnifaces.org/2015/09/what-mojarra-context-parameters-are.html) Even upgrading to Mojarra 2.2.12 / Omnifaces 2.2 / Primefaces 5.3 didn't make the difference and I got lost debugging already. I know it's a lot to ask, but as you already reproduced the initial problem and said you got it working you might have a short look on my example [here](https://drive.google.com/file/d/0ByIUO8bTcTZ2aGhMMmxYUV85RFE/view?usp=sharing) and try it in your sandbox - or provide me yours? THX. I owe you big time! – Ralf Dec 11 '15 at 13:59
  • Your code works for me when taken over in a completely empty project with everything set to default and only the mentioned context param set. Do you have any other context params in web.xml, particularly related to state saving? – BalusC Dec 11 '15 at 15:25
  • Thank you for trying. I feel a bit stupid. Even in a completely empty project with minimalistic settings with or without ´javax.faces.SERIALIZE_SERVER_STATE´ I still experience the same. No other context parameters. No spring. No filters. The web.xml is almost empty. faces-config.xml not used. I also tried another Browser, even another Webserver (TomEE) - but still the same. [This](https://drive.google.com/file/d/0ByIUO8bTcTZ2STZoR0Rrc0lrVXM/view?usp=sharing) is the very simple Eclipse (Maven build) Project if interested. – Ralf Dec 14 '15 at 14:23
  • I only had to set JSF API/impl to provided in pom.xml (because WildFly and TomEE already provides its own JSF API/impl out the box) and then it still works fine for me on WildFly 8.2.1, WildFly 9.0.1 and TomEE 7.0.0 (I couldn't use your project on a barebones Tomcat as you didn't have CDI explicitly installed). On the test page, I added a few new branches, filled out the color name and then pressed "Save". All filled out color names are present in the log. – BalusC Dec 14 '15 at 14:37
  • Thx for the provided hint. Just to be very sure we talk about exactly the same. You first added a few Branches and ALSO min. 1 field to the list of String input fields for each branch by clicking on **"+"**. (The first visible input field is not from the List but a simple Attribut of the branch to show they work) Only then you filled in some sample Data, pressed save and all the color fields are still in the screen + appeared in the log? If that's the case I will give myself the bullet today ;) Just kidding, but this gets really so f***ing strange I wanna cry... – Ralf Dec 14 '15 at 15:44
  • 1
    I didn't notice I could click on that tiny +. You're right, I can now reproduce your problem. Sorry for any inconvenience. Coming back to the concrete problem, it looks like `p:dataList` after all has the same problem as `ui:repeat`: not recognizing the `o:tree` as an iterator component. – BalusC Dec 14 '15 at 15:57
  • Sorry for the poor UI in this little showcase. At least I now got the proof I'm not crazy as I trusted more in your words than what I saw myself. ´ui:repeat´ is still a bit worse - it has not exactly the same behaviour as ´p:dataList´ as in ´ui:repeat´ the delete "-" link also doesn't work for the previous branches. My conclusion: As long as no input fields should be bound back to a Bean ´p:dataList´ and ´o:tree´ work fine together... Let's see how I'll overcome this restriction now in reality. – Ralf Dec 14 '15 at 16:17
  • @BalusC: PrimeFaces finally recognized several of the related problems and created a [`p:repeat`](https://github.com/primefaces/primefaces/issues/999) for this. Will be in a 5.2.x/5.3.x elite release and 6.0. But maybe (until Mojarra fixed it) an `o:repeat` would be an option to? – Kukeltje Jan 13 '16 at 20:30
  • @Kukeltje: indeed, already saw it in EG mailing. We have considered an o:repeat a long time ago (even before 1.0), but dropped it for reasons I don't exactly remember anymore. Perhaps we should reconsider. – BalusC Jan 13 '16 at 20:53