javaee / mojarra

PLEASE NOTE: This project has moved to Eclipse Foundation and will be archived under the JavaEE GitHub Organization. After Feb. 1, 2021, the new location will be github.com/javaee/mojarra. Mojarra - Oracle's implementation of the JavaServer Faces specification
https://github.com/eclipse-ee4j/mojarra
Other
164 stars 58 forks source link

Component id changes when an action modifies component tree #4200

Open javaserverfaces opened 7 years ago

javaserverfaces commented 7 years ago

We use to include our components into a form.

On included components we don't define ids just leverage on autogenerated component id for primefaces command button.

For a simplified example we start with 3 components with a on them. Initially component 1 and 3 is included to the form with second component is not included. As a result commandbutton action on component 1 we update only the container of the second component and includes the component between the existing two components. Commandbutton on component 2 receives the same id as commandbutton on component 3, so there are two buttons in the browser with the same id and the two commandbuttons call the same action.

If we update the whole form after the action instead of the target component we can see the commandbutton 3 receives a new id as well, but partial update riuns the view.

How can we make partial update work with our component structure? I attach our simplified example of the issue. We don't experience this issue on Websphere with myfaces.

Thanks

Environment

Wildfly 10.0.0 Final, Weblogic

Affected Versions

[2.2.8-12, 2.2.8-18, 2.3.0-m06]

javaserverfaces commented 7 years ago

Reported by szuni

javaserverfaces commented 7 years ago

szuni said:

**page.xhtml**    <h:form>
        <ui:decorate template="domincluder.xhtml">
            <ui:param name="subBean" value="#{insertDomBean.subBeanList[0]}"/>
        </ui:decorate>
        <p:outputPanel id="hidden">
            <c:choose>
<c:when test="#{insertDomBean.subBeanList[0].buttonPushed}">
    <ui:decorate template="domincluder.xhtml">
        <ui:param name="subBean" value="#{insertDomBean.subBeanList[1]}"/>
    </ui:decorate>
</c:when>
<c:otherwise>
    <p:outputLabel value="Button 1 not pushed"/>
</c:otherwise>
            </c:choose>
        </p:outputPanel>
        <p:outputPanel>
            <ui:decorate template="domincluder.xhtml">
<ui:param name="subBean" value="#{insertDomBean.subBeanList[2]}"/>
            </ui:decorate>
        </p:outputPanel>
    </h:form>
**domincluder.xhtml**<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:p="http://primefaces.org/ui"> 
    <p:commandButton value="#{subBean.text}" action="#{subBean.pushed()}" update="hidden"/>

</ui:composition>
**InsertDomBean.java**@Named
@ViewScoped
public class InsertDomBean implements Serializable{
    private List<SubBean> subBeanList;

    public InsertDomBean() {
        subBeanList = Arrays.asList(new SubBean("One"), new SubBean("Two"), new SubBean("Three"));
    }

    public List<SubBean> getSubBeanList() {
        return this.subBeanList;
    }

    public static class SubBean {

        private String text;
        private boolean buttonPushed;

        public SubBean(String text) {
            this.text = text;
        }

        public void pushed() {
            LOG.info(text);
            this.buttonPushed = true;
        }

        public boolean isButtonPushed() {
            return this.buttonPushed;
        }

        public void setButtonPushed(boolean buttonPushed) {
            this.buttonPushed = buttonPushed;
        }

        public String getText() {
            return this.text;
        }
    }
}
javaserverfaces commented 7 years ago

ren.zhijun.oracle said: can you provide me a runnable reproducer?

javaserverfaces commented 7 years ago

szuni said: Please place the provided .java and 2 .xhtmls from the comment above into a war and run it. After you pushed second button and try to push third you can see our problem.

javaserverfaces commented 7 years ago

ren.zhijun.oracle said: I have reproduced your issue:

1. In the first request, the whole page is rendered to client, the button3's clientid is j_idt9, the button2 is not rendered; 2. When Button1 is clicked, an AJAX request was sent, as response, only button 2's dom element was sent to client, and it's id is also j_idt9; so in the client side, Button2 and Button3 has equal client id(under the same form).

I found the root cause and it is really a JSF issue, it is due to basic and complicated algorithm for generating id during the component tree building up. To fix it, we need to change the current mechanism and this will be not a minor work and is very risky. We will consider it and check whether we can find a feasible way to handle.

Can it be fixed in PrimeFaces side? by implementing the class of the wrapped tag( p:outputPanel,) as a class of NamingContainer, so that client id of the button will be composed by FormId + p:outputPanel Id + button Id, this can ensure the id uniqueness of buttons in the client side.

javaserverfaces commented 7 years ago

Was assigned to ren.zhijun.oracle

javaserverfaces commented 7 years ago

This issue was imported from java.net JIRA JAVASERVERFACES-4196

edburns commented 6 years ago

Please see this important message regarding community contributions to Mojarra.

https://javaee.groups.io/g/jsf-spec/message/30

Also, please consider joining that group, as that group has taken the place of the old dev@javaserverfaces.java.net mailing list.

Thanks,

Ed Burns