0

I need to show a list of auction items. When a user clicks on a Bid button next to each item, I'd like to have ajax open a bid form right under this auction item. So I'm going with a ui:repeat and a f:ajax as shown below, but when I go to the page all the auction items have the bid component open next to them. And clicking any of the buttons doesn't do anything. This is the code (with the bid form simplified to just an outputText:)

<h:form>
<table border="1">
<ui:repeat var="parcel" varStatus="status" value="#{auctionsViewBean.parcels}">
<tr>
  <td><h:commandButton value="Bid" action="nothing">
      <f:ajax render="bidView"/>
  </h:commandButton></td>
  <td>#{status.index + 1}</td>
  <td>#{parcel.a}</td>
  <td>#{parcel.b}</td>
  <td>#{parcel.c}</td>
</tr>    
<tr><td><h:outputText id="bidView" value="#{auctionsViewBean.showBidViewForParcel(parcel)}">Some text</h:outputText></td></tr>

</ui:repeat> 
</table>
</h:form>

What am I doing wrong? And how can I specify only the bid component related to the clicked auction item?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Herzog
  • 923
  • 1
  • 14
  • 28

1 Answers1

2

If I understand you correctly, you want to initially hide the bidView until the button is pressed? You can do it by giving it a rendered attribute and put it in another component which can be referenced by <f:ajax>. You only need to rearrange the action method and checking logic.

<h:commandButton value="Bid" action="#{auctionsViewBean.addBidView(parcel)}">
<f:ajax render="bidView" />
...
<h:panelGroup id="bidView">
    <h:panelGroup rendered="#{auctionsViewBean.showBidView(parcel)}">
        ...
    </h:panelGroup>
</h:panelGroup>

with something like this:

public void addBidView(Parcel parcel) {
    bidViews.put(parcel, new BidView());
}

public boolean isShowBidView(Parcel parcel) {
    return bidViews.containsKey(parcel);
}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thanks for your reply, BalusC. Actually I do not have a nested form, and I said that the code above is simplified only because I removed some of the elements in the table. In short, if I could have this code above working I'll be good. So I guess the question is: how do I get the "bidView" element not to be there when the page is rendered at first, and only appear for the clicked auction once it's clicked? (It's a total newbie question, I'm sure I'm missing something simple here..) – Herzog Nov 20 '11 at 15:49
  • Ah right. Your question was after all ambiguous and your wrong attempt has put me on the wrong track of understanding what you really needed (basically, I understood that in your case the `` didn't do anything -which is untrue). I updated the answer. – BalusC Nov 21 '11 at 03:03
  • Thank you very much for taking the time, BalusC. It works now, but only partially. When I go to the page the components are hidden. When I click on the button the correct one is shown. So far so good. But it seems like the isShowBidView is being called for each iteration of the loop -- up to the row where I clicked the button. So for example if there are 4 rows, and I click on the button next to the third, isShowBidView is called for the 1st, 2nd, and 3rd rows. It is correctly false for the first two, and true for the third, also correctly. What's going on? – Herzog Nov 21 '11 at 09:36
  • Also, subsequent clicks on any of the Bid buttons on the page seem to generate multiple calls (7 calls, to be exact) to isShowBidView from ALL the rows in the loop. Are the multiple auctionsView.xhtml components being generated? I'm at a loss here. – Herzog Nov 21 '11 at 09:37
  • The `rendered` attribute is indeed called multiple times on a single component. For detailed explanation, see http://stackoverflow.com/questions/4281261/why-is-the-getter-called-so-many-times-by-the-rendered-attribute That's why it is so important that those calls should be cheap (i.e. do not do any business logic or database access in the getters). – BalusC Nov 21 '11 at 11:25
  • OK, I get the lifecycle issue. On to the next, and thank you again for your time. It looks like in my case when I'm clicking any of the buttons, all the buttons are being clicked because the isShowBidView(Parcel parcel) is getting called *for each* of the rows up to the row I clicked on. I thought the problem could be in the commandButton declaration and tried to give it a unique ID in each row, but setting id="#{status.index}" generated an "Empty id attribute is not allowed" exception. Any help would be greatly appreciated. – Herzog Nov 21 '11 at 12:09
  • Well, I looked at the page source and JSF is giving each button a unique ID. So that's not the problem here. – Herzog Nov 21 '11 at 13:10
  • I do also not understand your concrete problem. All I can boil down out of it is that you're complaining that getters are called multiple times. That's normal and this should not harm if they do not do any business logic, but just return the data which is been asked for. Or do you have a functionality problem in the UI side? E.g. buttons not working, rendering not working, etc. – BalusC Nov 21 '11 at 13:12
  • OK. Solved it. Embarrassed to even say what it was. Totally my mess. Nothing related to JSF. Thank you very much BalusC, you helped a lot. – Herzog Nov 21 '11 at 16:32