AlexSC
AlexSC

Reputation: 1943

How to maintain a list of objects in Java Server Faces 2

I have a JSF2 application that should show a page where a number os items must be added in a list. The user wants to add those items, set some properties of them and finally persist them all together, in a single save operation.

The domain object that should be handled by this page looks like this:

public class Item {
    private long id;
    private String name;
    private Item previous;

    public Item() { }

    public Item(Item previousItem) {
        this.previous = previousItem;
    }

    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public Item getPrevious() {
        return previous;
    }

}

The ItemBean class looks like this:

@ManagedBean
public class ItemBean implements Serializable {
    private static final long serialVersionUID = 1L;

    private List<Item> items = new ArrayList<Item>();

    public List<Item> getItems() {
        if(items.size()==0) {
            items.add(new Item()); // adding the first item
        }
        return items;
    }

    public void setItems(List<Item> items) {
        this.items = items;
    }

    public void addItem(Item previousItem) {
        Item newItem = new Item(previousItem);
        items.add(newItem);
    }

    public void save() {
        ...
    }
}

The view is a xhtml file that looks like this:

<?xml version='1.0' encoding='UTF-8' ?>  
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets">
<body>
<ui:composition template="/templates/layout.xhtml">
<ui:define name="content">
<h2>Items</h2>
<fieldset>
    <legend>Items being added</legend>
    <ui:repeat value="#{itemBean.items}" var="item">
    <div>
        <h:outputLabel value="Item" for="name" />
        <h:inputHidden value="#{item.id}" />
        <h:inputText id="name" value="#{item.name}" />
        <h:commandLink action="#{itemBean.addItem(item)}">Add</h:commandLink>
    </div>
    </ui:repeat>
</fieldset>
<div class="options">
<h:commandButton action="#{itemBean.save}" value="Save"/>
<div class="clear border-bottom"></div>
</div>
</ui:define>
</ui:composition>
</body>
</html>

Notice that in order to add a new item, the current one must be sent to satisfy business rules.

The problem is that I can add a second item with no problema, but when I click in the Add link next to the second item, the page is rerendered with one single item, just like it was in the beggining.

Unfortunatelly, I can't see what's missing to make it work, even after reading a lot of posts, pages and some book chapters.

Update 1

I was asked about the kind of scope used with this bean. It´s de default scope (@RequestScoped). I was trying to avoid using @SessionScoped for the sake of scalability, but in this particular case, I´m not sure I have a choice. Anyone with more experience could give me tip?

Upvotes: 1

Views: 428

Answers (3)

Thrax
Thrax

Reputation: 1964

What is the scope of your ManagedBean ?

Since you didn't post any persistence code, I suppose the items List only exists througout your Bean's life. This means that if your Bean is @ViewScoped or @RequestScoped, your items cease to exist after you submit your form.

Upvotes: 2

Maxime
Maxime

Reputation: 190

I see no form in your xhtml page like :

<h:form>
    <ui:repeat>
        <h:inputBlabla/>
    </ui:repeat>
</h:form>

A form is needed while using h:input fields.

Upvotes: 0

BlackBlaze
BlackBlaze

Reputation: 254

You need use an ajax component, something like:

<fieldset id="list">
    <legend>Items being added</legend>
    <ui:repeat value="#{itemBean.items}" var="item">
    <div>
        <h:outputLabel value="Item" for="name" />
        <h:inputHidden value="#{item.id}" />
        <h:inputText id="name" value="#{item.name}" />
        <h:commandLink action="#{cargoBean.addItem(item)}">
            <f:ajax render="list" />
                Add
        </h:commandLink>
    </div>
    </ui:repeat>
</fieldset>

Upvotes: 0

Related Questions