Search code examples
jsfjsf-2dynamic-forms

How to dynamically add JSF components


Can I add JSF components dynamically? I need to have a form with a button which should add one <h:inputText> to the form. Is this possible?

I know this should be possible in JavaScript somehow. Do anybody know how to do this in JSF? I think the major problem is how do I get or set values of new inputs via #{value}.


Solution

  • Use an iterating component like <h:dataTable> or <ui:repeat> to display a dynamically sized List of entities. Make the bean @ViewScoped to ensure that the list is remembered across postbacks on the same view instead of recreated over and over.

    Kickoff example with <h:dataTable> (when using <ui:repeat> simply replace <h:dataTable> by <ui:repeat>, and <h:column> by e.g. <li> or <div>):

    <h:form>
        <h:dataTable value="#{bean.items}" var="item">
            <h:column><h:inputText value="#{item.value}" /></h:column>
            <h:column><h:commandButton value="remove" action="#{bean.remove(item)}" /></h:column>
        </h:dataTable>
        <h:commandButton value="add" action="#{bean.add}" />
        <h:commandButton value="save" action="#{bean.save}" />
    </h:form>
    

    Managed bean:

    @Named
    @ViewScoped
    public class Bean {
    
        private List<Item> items;
    
        @PostConstruct
        public void init() {
            items = new ArrayList<>();
        }
    
        public void add() {
            items.add(new Item());
        }
    
        public void remove(Item item) {
            items.remove(item);
        }
    
        public void save() {
            System.out.println("items: " + items);
        }
    
        public List<Item> getItems() {
            return items;
        }
    
    }
    

    Model:

    public class Item {
    
        private String value;
    
        public String getValue() {
            return value;
        }
    
        public void setValue(String value) {
            this.value = value;
        }
    
        public String toString() {
            return String.format("Item[value=%s]", value);
        }
    
    }
    

    See also: