How to implement a dynamic list with a JSF 2.0 Composite Component?
Asked Answered
S

1

16

I asked this question and although the answer directly satisfied my needs I am left with a feeling that there has to a simpler solution for this specific problem.

I would like to have a composite component that accepts a list of items (The type of the items agreed upon so the members can be used freely within the composite component)

The CC (composite component) display the list of items and allows for addition and subtraction of items.

I would like to do this in the most simple and efficient manner.

To illustrate the problem, an example:

enter image description here

The definition should be rather simple (unless of course, its not :-) ):

<special:dynamicFieldList value="#{bean.fieldList} />

The most abstract form of a Field object would be:

public class Field{
 String uuid;
 String value;
}

I guess that's it. How would you implement this in a simple manner?

Thanks!

Snivel answered 15/6, 2011 at 13:2 Comment(0)
C
25

I'd use a <h:dataTable> in a composite component with a backing UIComponent which you can bind by componentType attribute of the <composite:interface>. In the backing UIComponent you can then maintain the DataModel and define the actions.

dynamicFieldList.xhtml

<ui:composition
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:cc="http://java.sun.com/jsf/composite"
>
    <cc:interface componentType="dynamicFieldList">
        <cc:attribute name="value" type="java.util.List" required="true" />
    </cc:interface>
    <cc:implementation>
        <h:dataTable id="table" binding="#{cc.table}" value="#{cc.attrs.value}" var="field">
            <h:column><h:outputLabel value="#{field.label}" /></h:column>
            <h:column><h:inputText value="#{field.value}" /></h:column>
            <h:column><h:commandButton value="remove" action="#{cc.remove}" /></h:column>
        </h:dataTable>
        <h:commandButton value="add" action="#{cc.add}" />
    </cc:implementation>
</ui:composition>

(the <h:inputText> can if necessary be your composite field component)

com.example.DynamicFieldList

@FacesComponent(value="dynamicFieldList") // To be specified in componentType attribute.
@SuppressWarnings({"rawtypes", "unchecked"}) // We don't care about the actual model item type anyway.
public class DynamicFieldList extends UINamingContainer {

    private UIData table;

    public void add() {
        ((List) getAttributes().get("value")).add(new Field("somelabel"));
    }

    public void remove() {
        ((List) getAttributes().get("value")).remove(table.getRowData());
    }

    public UIData getTable() {
        return table;
    }

    public void setTable(UIData table) {
        this.table = table;
    }

}

Use it as follows:

<h:form>
    <my:dynamicFieldList value="#{bean.fields}" />
</h:form>

with just this

@ManagedBean
@ViewScoped
public class Bean implements Serializable {

    private List<Field> fields;

    public Bean() {
        fields = new ArrayList<>();
    }

    public List<Field> getFields() {
        return fields;
    }

}

and

public class Field implements Serializable {

    private String label;
    private String value;

    public Field() {
        //
    }

    public Field(String label) {
        this.label = label;
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

}
Callan answered 15/6, 2011 at 13:18 Comment(5)
@Callan Tnx. But how do I encapsulate it into a composite component? Do I have to pass the "remove" and "add" methods as attributes? I guess that would be acceptable..Snivel
I updated the answer. Key point is to use a "backing UIComponent" where you define the actions.Callan
Nice one! :) I do wonder about the embedded form in the composite component. It's convenient as given, but also means this particular component can not be used inside another form.Lam
@Arjan: it makes indeed more sense to keep the form outside. I'll edit the example.Callan
Is this solution still valid for JSF 2.2?? As in my case add / remove buttons don't work. Thank you!Autoharp

© 2022 - 2024 — McMap. All rights reserved.