1

I am using JSF 2 with Glassfish 4. I would like to create an object that has a collection of objects as one of its fields. When searching, I can only find ways to display a collection field in a JSF form. Here I want the opposite: allow the user to populate this collection while creating the parent object. Simplified example below:

Parent Object: Account

public class Account {
    private String accountName;
    private List<Order> orderList = new ArrayList<Order>();

    public String save() {
        System.out.println(accountName);
        System.out.println(orderList);
        return "";
    }

    // Constructors, getters and setters below.

}

Child Object: Order

public class Order {
    private String orderName;
    private Integer orderCost;

    // Constructors, getters and setters below.

}

JSF Page Body

The idea for the form was taken from BalusC's answer here.

<h:body>
  <h1>Create Account</h1>
  <h:form>
    <h:panelGrid>
      Account Name: 
      <h:inputText value="#{account.accountName}" />

      <ui:repeat value="#{account.orderList}" varStatus="loop">
        Order Name:
        <h:inputText value="#{account.orderList[loop.index]}" />
        Order Cost:
        <h:inputText value="#{account.orderList[loop.index]}" />
      </ui:repeat>

    </h:panelGrid>
    <h:commandButton action="#{account.save}" value="Create" />
  </h:form>
</h:body>

I run into a few problems:

  • It's impossible for me to have a set number of Orders displayed. (ex: max 5 per new account). An input field is only displayed if the List already has some objects. This makes sense, but I would like to present the user with X blank lines they can fill in.
  • I am unable to expose both the orderName and orderCost fields at once to the user.
  • Later on I would like to add a commandButton that adds another row of inputText fields in the UI so the user can add however many orders to an account as they want.

Any help greatly appreciated. Happy to answer questions for anything I missed. Thank you!


After BalusC's help I made the following changes and I now have the behaviour that I want:

// Prop up the array so the desired number of fields appears in the UI
@PostConstruct
public void prepare() {
    orderList.add(new Order());
    orderList.add(new Order());
    orderList.add(new Order());
}

Iterate through the list of empty Order objects. No data is disabled since all field values in the Order objects are null. Also, since I created the objects in @PostConstruct, the user's changes are easily saved on Submit.

  <ui:repeat value="#{account.orderList}" var="order">
    Order Name:
    <h:inputText value="#{order.orderName}" />
    Order Cost:
    <h:inputText value="#{order.orderCost}" /><br/>
  </ui:repeat>
Community
  • 1
  • 1
Lev
  • 100
  • 8

1 Answers1

0

As to preparing a fixed amount of items and adding a new item, just add a new item to the list.

orders.add(new Order());

Do this in @PostConstruct to prepare the items on page load and do the same in "Add" button.

As to accessing properties, you don't need the varStatus/index trick as you've there a collection of mutable objects, not a collection of immutable objects (where the question you found was all about).

<ui:repeat value="#{bean.orders}" var="order">
    <h:inputText value="#{order.name}" />
    <h:inputText value="#{order.cost}" />
</ui:repeat>

If you really insisted to, you could have done #{bean.orders[loop.index].name}, but as said, this is unnecessary.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555