2

I'm working on old system which has a lot of code written back in the days using jsf1.2. Now I have the task to dynamically add/remove group of input elements via ajax on button click.

I was guided by this post on how to add input fields dynamically, made little tweaks to support ajax and made prove of concept which works perfectly fine. Now the problem occurs when instead of <h:inputText> .. </h:inputText> or other form fields I use our own custom tag component.

When using the custom tag I get the page displayed on page load, but if I try to remove an item, for the first component in the list I get the error java.io.IOException: Cannot add the same component twice: editform:parentTable:0:fieldsTable:0:HTML_TITLE_INPUT_en

I believe the problems is due to the component already being in the component tree when the custom tag tries to add it again on postback, but still I don't know how to fix the issue.

Note 1: I have to use our custom tag since it has a lot of logic inside and it is used to display every type of form field (inputText, textarea, checkboxes etc)

xhtml code:

<h:dataTable id="parentTable" value="#{bean.groups}" var="group" styleClass="parentTableStyleClass">

    <h:column>
        <h:dataTable id="fieldsTable" value="#{group.fields}" var="field">

            <h:column>
                <h:outputLabel value="#{field.label}" styleClass="col-sm-2 control-label" />
            </h:column>

            <h:column>
                <customTag:propertyValue
                        name="#{field.name}"
                        operation="edit"
                        instance="#{bean.instance}"
                        styleClass="form-control"
                        inputWrapperClass="col-sm-5"/>
            </h:column>

        </h:dataTable>
    </h:column>

    <h:column>
        <p:commandButton value="Remove Group"
                         styleClass="btn btn-secondary btn-sm"
                         action="#{bean.removeGroup(group)}"
                         process="@(.parentTableStyleClass)"
                         update="@(.parentTableStyleClass)" />
    </h:column>
</h:dataTable>

The tag class:

public void encodeBegin(FacesContext context) throws IOException {
    getChildren().clear();

    ...
    // bunch of logic
    ...

    HtmlPanelGroup wrapper = new HtmlPanelGroup();
    HtmlInputText inputText = new HtmlInputText();
    ...
    // bunch of code creating input text field
    ...
    wrapper.setStyleClass(getInputWrapperClass() + " input-group");
    wrapper.getChildren().add(inputText);
    getChildren().add(wrapper);

}
Community
  • 1
  • 1
ontime
  • 113
  • 2
  • 7
  • Have you solved this? – Phellipe Ribeiro Nov 23 '16 at 18:51
  • @PhellipeKelbert Yes I solved it but I don't think my solution is the right one as it looks way too hacky. Instead of h:dataTable I'm using jstl's c:foreach, whenever I need conditional rendering I use both c:if (otherwise I get 'Cannot add the same component') and components rendered tag (otherwise I get the same component twice after ajax update). One last thing was to add an int value in my ViewScope bean which is incremented on every ajax request, that value is then forwarded to the component tag as a tag attribute and is used to always generate a new unique ID (intValue + componentName) – ontime Nov 24 '16 at 17:07

0 Answers0