3

I have a p:accordionPanel which represents a list of items and in each tab there is a form. Upon submitting any of the repeating forms, it is possible that extra data in needed, which is when a p:dialog is popped up prompting the user to enter some more data. That dialog is defined outside the accordion panel because, unlike the items from the accordion, only one of them can be showing at a time so there is no need to augment the HTML served by repeating it in each tab of the accordion.

The definition of the accordion looks as follows (simplified but with all the relevant descriptors):

<p:accordionPanel id="myAccordion" value="#{managedBean.getAccordionList}" var="item" multiple="false" dynamic="true" cache="true">

    <p:ajax event="tabChange" listener="#{managedBean.processTabChange}"/>

    <p:tab title="#{item.tabTitle}" id="itemTab">

        <h:form id="itemForm">

            <h:outputLabel for="itemName" value="Item Name:"/>
            <p:inputText id="itemName" title="Item Name:" 
                    maxlength="16" value="#{appeal.itemName}">
            </p:inputText>

Consequently, the HTML rendered for itemName is myAccordion:0:itemForm:itemName in the first instance, myAccordion:1:itemForm:itemName in the second, etc.

The dialog is defined as follows:

<p:dialog id="commentDialogID" header="Enter comment" widgetVar="commentDialog" modal="true" resizable="true" height="auto">
    <h:form id="commentForm">

        <h:outputLabel for="comment" value="Comment:"/>

        <p:inputTextarea id="comment" title="Comment" 
                rows="6" cols="33"
                value="#{managedBean.activeItem.comment}"
                required="true">
            <f:ajax render="comment"/>
        </p:inputTextarea>

        <h:commandButton value="Submit" action="#{managedBean.proceed}" onclick="PF('commentDialog').hide();">
            <f:ajax render="*** ??? ***"/>
        </h:commandButton>

    </h:form>
</p:dialog> 

What I have repeatedly been failing at are attempts to f:ajax update only a single tab in the accordion panel, the active one from which the dialog was popped up. I tried using

:myAccordion:#{managedBean.activeItem.displayIndex}:itemForm:itemName
:myAccordion:#{managedBean.activeItem.displayIndex}:itemForm
:myAccordion:#{managedBean.activeItem.displayIndex}:itemTab

in place of *** ??? *** but none of them would compile:

javax.faces.FacesException: <f:ajax> contains an unknown id ':myAccordion:0:itemForm' - cannot locate it in the context of the component j_idt20

If I skip the index token (e.g. :myAccordion:itemForm:itemName) it does compile but it does functionally nothing. The Item entity class has a getDisplayIndex which does accurately return the index of the active tab.

My problem is quite similar to that which is described in this question, which doesn't really have a good answer. Could it be a limitation of PrimeFaces?

Community
  • 1
  • 1
amphibient
  • 29,770
  • 54
  • 146
  • 240
  • "Could it be a limitation of PrimeFaces?" I'd say not. That doesn't make any sense. – DavidS Jul 16 '15 at 17:17
  • I meant a bug, @DavidS – amphibient Jul 16 '15 at 17:41
  • One thing I'm curious about is what is rendered for `f:ajax`. You say you're trying to use `displayIndex` in the `render` attribute, but the `f:ajax` itself is rendered only once. For example, for a similar example with a static accordion panel, the ajax button is rendered as `onclick="mojarra.ab(this,event,'action',0,'form:myaccordion:mytab2');return false"`. Maybe you've already accounted for this? – DavidS Jul 16 '15 at 17:49
  • Nothing because the JSF fails to compile and I get an error on the page saying that `:myAccordion:0:itemForm:itemName cannot locate it in the context of the component j_idt20`. However, if I skip the index token (e.g. `:myAccordion:itemForm:itemName`) it does compile but it does nothing – amphibient Jul 16 '15 at 18:04
  • The question has been updated to reflect your inquiry, @DavidS – amphibient Jul 16 '15 at 18:09
  • Maybe [this is relevant](http://stackoverflow.com/a/8644762/201891), see "Referencing specific iteration round of iterating components". The PrimeFaces documentation states that dynamic accordion tabs are rendered similarly to `ui:repeat`, so maybe you've encountered that limitation. I'm not certain – DavidS Jul 16 '15 at 18:16

2 Answers2

1

I don't know what version of Primefaces you are using, but this seems to be a bug in Primefaces 5.1.1 where i could recreate this issue. By upgrading to Primefaces 5.2, the ajax EL could suddenly find the referenced id. I can post a MCVE if needed.

Edit: The MCVE:

XHTML:

<h:form id="itemForm">
    <p:accordionPanel id="myAccordion" binding="#{accordionView}" value="#{playgroundController.users}" dynamic="true" activeIndex="#{playgroundView.activeIndex}" var="user" multiple="false">

        <p:ajax event="tabChange" update="commentDialogID"/>

        <p:tab title="#{user.name}">
                <h:outputLabel for="itemName" value="Item Name:" />
                <p:inputText id="itemName" title="Item Name:" maxlength="16"
                    value="#{user.amount}">
                </p:inputText>
                <p:commandButton value="showDialog" onclick="PF('commentDialog').show();"></p:commandButton>
        </p:tab>

    </p:accordionPanel>
</h:form>

<p:dialog id="commentDialogID" header="Enter comment" widgetVar="commentDialog" modal="true" resizable="true" height="auto">
    <h:form id="commentForm">

        <h:outputLabel for="comment" value="Comment:"/>

        <p:inputTextarea id="comment" title="Comment" 
                rows="6" cols="33"
                value="#{playgroundView.activeIndex}"
                required="true">
            <f:ajax render="comment"/>
        </p:inputTextarea>

        <p:commandButton value="Submit" onclick="PF('commentDialog').hide();" update=":itemForm:myAccordion:#{playgroundView.activeIndex}:itemName" ></p:commandButton>

    </h:form>
</p:dialog> 

PlaygroundView Bean:

Note that in this example the activeIndex has to have an initial value, otherwise this EL:

update=":itemForm:myAccordion:#{playgroundView.activeIndex}:itemName"

will resolve wrongly and will throw an error that it cannot find the id of the referenced component. This of course has the drawback that the first tab will be open when the page loads, but that's another issue

private String activeIndex = "0";

public String getActiveIndex() {
    return activeIndex;
}

public void setActiveIndex(String activeIndex) {
    this.activeIndex = activeIndex;
}

PlaygroundController Bean:

private List<User> users;
@Override
    public void initializeView() {
    createUsers();
}

public void createUsers() {
        User user1 = new User();
        User user2 = new User();
        User user3 = new User();
        user1.setName("User123");
        user1.setAmount(1);
        user2.setName("User456");
        user2.setAmount(2);
        user3.setName("User12312345111111111111111111111111111");
        user3.setAmount(3);
        List<User> userList = new ArrayList<User>();
        userList.add(user1);
        userList.add(user2);
        userList.add(user3);
        users = userList;
    }

User:

public class User implements Serializable {
    String name;
    int amount = 0;
}
Vasil Lukach
  • 3,658
  • 3
  • 31
  • 40
Emil Kaminski
  • 1,886
  • 2
  • 16
  • 26
0

You should update the commandButton on the tabChange event.

<p:ajax event="tabChange" listener="#{managedBean.processTabChange}" update=":commentForm:commandButtonId"/>

The render attribute <f:ajax> inside the <h:commandButton>is evaluated during the render phase and not sooner afaik. So if you do not update it, it will always point to '0'. Check the source in your browser developer tool and check your ajax requests (things you should always do for debugging). You will see the full clientId with the ':0:' and you will not see it changing on the ajax requests.

Kukeltje
  • 12,223
  • 4
  • 24
  • 47
  • I tried that, however, there is a problem with updating `:commentForm:commandButtonId` and i think it may be because it has a nested `f:ajax` – amphibient Jul 16 '15 at 23:40
  • **what** problem? We are not clairvoyant. And tried a `p:commandButton`? – Kukeltje Jul 17 '15 at 02:31
  • Hmmm, I see all kinds of comments now above, no idea why I did not see those… And an updated question. Could indeed be the same problem/limitation – Kukeltje Jul 17 '15 at 02:43
  • According to the rendered HTML/JS, the tab change update of the dialog's AJAX, as per your suggestion, does not take effect as the PF function does not change to reflect the tab index. i debugged and `getDisplayIndex` does get invoked but, for some reason, the rendered content is not being changed – amphibient Jul 17 '15 at 16:37
  • i also changed both `commandButton` and `ajax` to be `p` instead of `f` but that did not help – amphibient Jul 17 '15 at 16:38
  • What PF function? EL does not contain any PFfunction? And regarding the getDisplayIndex, does it change? Do you set it somewhere? – Kukeltje Jul 17 '15 at 16:41
  • the JSF compiler converts the EL function to a PF javascript call in the actual HTML rendering. it looks like `PrimeFaces.bcn(this,event,[function(event){PrimeFaces.ab...` – amphibient Jul 17 '15 at 16:46
  • Then check if you update it from the tabchange event, if it is in theajax response. Check the network tab of your browser – Kukeltje Jul 17 '15 at 17:12