Pregunta

I am trying to display HtmlInputText dynamically in a JSF page. However, I am getting

javax.faces.FacesException: Cannot add the same component twice: j_idt10:hitDyn

During the first request to the page the input text renders well. That exception happens during postback of the page, when I enter some text in the input component and press Enter. In the .xhtml page, I have the following code:

<h:form>
    <h:outputLabel value="Welcome!"></h:outputLabel>
    <f:metadata>
        <f:event type="preRenderView" listener="#{dynamicBacking.addDynComp}" />
    </f:metadata>
    <h:panelGroup id="dynOuter"></h:panelGroup>
</h:form>

In the backing bean, I have the following code:

@ManagedBean(name="dynamicBacking")
public class DynamicBacking {
    public void addDynComp() {
        Application app = FacesContext.getCurrentInstance().getApplication();
        HtmlInputText hit = (HtmlInputText)app.createComponent(HtmlInputText.COMPONENT_TYPE);
        hit.setId("hitDyn");
        UIComponent parent = findComponent("dynOuter");
        if( parent != null ) {
            parent.getChildren().add(hit);
        }
    }

    public UIComponent findComponent(final String id) {
        FacesContext context = FacesContext.getCurrentInstance(); 
        UIViewRoot root = context.getViewRoot();
        final UIComponent[] found = new UIComponent[1];
        root.visitTree(new FullVisitContext(context), new VisitCallback() {     
            @Override
            public VisitResult visit(VisitContext context, UIComponent component) {
                if(component.getId().equals(id)){
                    found[0] = component;
                    return VisitResult.COMPLETE;
                }
                return VisitResult.ACCEPT;              
            }
        });
        return found[0];
    }
}

I guess that there is some problem with restoring the state of the dynamic component in a postback. Am I adding the dynamic component too late in the lifecycle of the JSF page? I know that in ASP.NET I could add a dynamic control during Page.Load phase. But I can't so far figure out how to achieve the same in JSF. Please, help!

¿Fue útil?

Solución

The exception appears because the component is added in the tree on the initial page load. When performing a postback your listener gets called again and it tries to add another component with the same id and this causes the exception. A solution of the issue is to check if the request is NOT a postback when adding the component. The following code shows how to check for postback:

if (FacesContext.getCurrentInstance().isPostback()) {....
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top