33

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}.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
ErVeY
  • 1,524
  • 4
  • 16
  • 26

3 Answers3

36

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:

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 1
    thanks, was thinking the same thing, only wondering if it was the best way to do it = D – ErVeY Aug 05 '10 at 14:05
  • 5
    True. The only alternative would be creating components programmatically like `new HtmlInputText()` and so on, but that would only result in nasty and opaque code in managed bean. – BalusC Aug 05 '10 at 14:11
  • Hi, @BalusC, is it appropriate to add a field "name" to Item class? I need to save the items into DB and i must read them from DB too. – merveotesi Dec 26 '11 at 12:00
  • I did just this approach. But when I enter a new value on the added input and hit submit, the list on the backing bean is not updated. What can be wrong? My items are a List, could be it? It can't change the string on the List? – JSeven Apr 29 '14 at 20:47
  • @JSeven: [The `String` class is indeed immutable](http://stackoverflow.com/questions/10780858/using-uirepeathinputtext-on-a-liststring-doesnt-update-model-values/). Every Java developer should know this. – BalusC Apr 29 '14 at 20:58
  • I know that. I followed this answer http://stackoverflow.com/questions/3690317/how-to-add-hinputtext-dynamically-in-jsf and since I don't know precisely the inner workings of JSF, I thought it could maybe replace the String on the list with the new one instead of changing it. – JSeven Apr 29 '14 at 21:06
  • @JSeven: Awkward. I posted a comment over there to protect the future innocent. – BalusC Apr 29 '14 at 21:19
  • This is so much better than what Ive been doing thanks – Ced Oct 30 '15 at 07:45
  • Hi, @BalusC, if there are other inputs (beside the dynamic one) in the form with a set of validations or are marked as required then how to achieve the same thing? In my case, the action won't execute at all if there are validation errors. – Habib Rosyad Oct 05 '17 at 06:34
  • @BalusC Thank you very much man! I am new in jsf and you saved my day! Actually i am using oracle adf and jdeveloper. Is there any way i can set the bean state through interface in jdeveloper. – Bino May 08 '18 at 13:56
1

It's should be like that

Bind a form tag to the bean property


<form binding="#{myBean.myform}">...</form>

@ManagedBean("myBean")
public class Bean{
   property HtmlForm myform;
}

on event, create a new instance of the input component

HtmlInputText input=new HtmlInputText();

and attach to the your form

myform.getChildren().add(input);
corsair
  • 658
  • 5
  • 14
  • 2
    Please never create new component instances yourself. The prefered way is this: `FacesContext.getCurrentInstance().getApplication().createComponent(HtmlInputText.COMPONENT_TYPE);` – dforce Mar 16 '17 at 07:41
0

Use h:dataTable to add elements dynamically... Have a list of any type you want to provide values for dataTable...

In h:dataTable... you can include the element tag to create inside <h:column>

It will be used to generate elements you want to create dynamically.

Adrián
  • 6,135
  • 1
  • 27
  • 49
Arun
  • 825
  • 4
  • 14
  • 31
  • 2
    Welcome at Stack Overflow! This answer doesn't seem to add anything substantial on top of the already given answers so far. Stack Overflow is not a discussion forum where everyone repeats each other on agreement, but it is a question&answer site where everyone gives an upvote on agreement or a downvote on disagreement. If you earn 15 reputation, then you can cast upvotes. – BalusC Jan 24 '13 at 11:12