How to Dynamically add a row in a table in JSF?
Asked Answered
B

2

8

In my application i need to add a row on a click of a button and this button will be in all the rows. Need help to do this?

Item Class

public class Item {
 public Item()
{

}
private String value;
public Item(String value) { this.value = value; }
public void setValue(String value) { this.value = value; }
public String getValue() { return value; }
}

Manage Bean Class

public class MyMB 
{
private List<Item> list;    

public void addItem() { // JSF action method
    list.add(new Item("Default"));
    Iterator<Item> iterator = list.iterator();
    while(iterator.hasNext())
    {
        Item item = (Item)iterator.next();
        System.out.println(item.getValue());
    }
    System.out.println();
    }
/**
 * @return the list
 */
public List<Item> getList() {
    if(list==null)
    {
        loadList();
    }
    return list;
}
private void loadList() {
    list = new ArrayList<Item>();
    list.add(new Item("Data"));
}

}

JSF code

<h:form>
   <rich:dataTable value="#{myMB.list}" var="item" id="tabel">
    <h:column><h:inputText value="#{item.value}" /></h:column>
    <h:column><a4j:commandButton value="Add"  actionListener="#{myMB.addItem}" reRender="tabel"/></h:column>

Builtin answered 17/2, 2010 at 4:40 Comment(0)
P
10

All you need to do is basically indeed just adding an empty object to the datamodel behind the value attribute of h:dataTable.

But the same empty row needs to be preserved in the subsequent request as well. If the backing bean is request scoped, then the datamodel get reloaded without the empty row. This all should work when the bean is session scoped.

Further there are several errors in your JSF code. The h:dataTable var attribute is missing and the column content needs to be inside a h:column.

<h:form>
    <h:dataTable value="#{bean.list}" var="item">
        <h:column><h:inputText value="#{item.value}" /></h:column>
    </h:dataTable>
    <h:commandButton value="Add" action="#{bean.add}"/>
</h:form>

A session or view scoped bean can look like this:

public class Bean {
    private List<Item> list;

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

    public void add() {
        list.add(new Item());
    }

    public List<Item> getList() {
        return list;
    }
}

The Item class should of course have a default no-arg constructor. Normally this is already implicitly available, but if you define your own constructor with arguments, then it is not available anymore. You'll need to explicitly define it, otherwise you cannot do Item item = new Item(); anymore.

public class Item {

    private String value;

    public Item() {
        // Keep default constructor alive.
    }

    public Item(String value) {
        this.value = value;
    }

    // ...
}

If you prefer to keep the bean in the request scope, then you'll need to maintain the amount of newly added items, so that the bean can preserve the same amount on load.

public class Bean {
    private List<Item> list;
    private HtmlInputHidden count = new HtmlInputHidden();

    public Bean() {
        count.setValue(0);
    }

    public void add() {
        list.add(new Item());
    }

    public List<Item> getList() {
        if (list == null) loadList();
        return list;
    }

    public HtmlInputHidden getCount() {
        return count;
    }

    public void setCount(HtmlInputHidden count) {
        this.count = count;
    }

    private void loadList() {
        list = new ArrayList<Item>();

        // Preserve list with newly added items.
        for (int i = 0; i < (Integer) count.getValue(); i++) {
            list.add(new Item());
        }
    }
}

You'll only need to add the following to the <h:form> of the JSF page:

<h:inputHidden binding="#{bean.count}" converter="javax.faces.Integer" />

For more insights about using datatables in any way you may find this article useful: Using Datatables. It also contains a WAR file with lot of examples in both request and session scope.

Panelboard answered 17/2, 2010 at 11:26 Comment(4)
@Panelboard : I have a doubt in this technique, when i press the button the whole page is refreshed right, can we do this whole thing using Ajax so that this process is asynchronous.Builtin
Yes you can. As you aren't using JSF 2.0 yet, you'll need to plug some 3rd party component library in. I can recommend you the Ajax4jsf subcomponent of JBoss RichFaces. To learn more: jboss.org/file-access/default/members/jbossajax4jsf/freezone/…Panelboard
With the link provided by you,I tried to change the code to support ajax.I am getting a error that '#{myMB.addItem}' Method not found:....But i have that method in the Bean class. i have editted my code...Kindly HelpBuiltin
Use action instead of actionListener, or change addItem to take an ActionEvent argument.Panelboard
E
2

Take this table as an example:

<h:datatable value="#{myBean.list}" ...>
    ...
    <h:column>
       <h:commandButton value="Add a row" action="#{myBean.addRow}"/>
    </h:column>
</h:datatable>

The method myBean.addRow will simply add a new element in your list:

public class MyBean {

    private List<SomeClass> list;

    ...

    public List<SomeClass> getList() {
        return list;
    }

    public void addRow() {
        list.add(new SomeClass());
    }
}

When you will click on the button, the method addRow will add a new element in the list. The page will refresh and display the table with a new row.

Edit:

Regarding your post edition, three things:

Point 1: Could you please attach the stacktrace of your error?

Point 2: Your method addRow return a String which is an ID used by JSF for the navigation. As this action does not involve any navigation (i.e. the user stay on the same page), simply return null or "":

public String addRow() {
    list.add(new Item("new data"));
    return null;
}

Point 3: I suggest that your class Item provide an empty constructor (in addition of your current constructor):

public Item() {
}
Exhort answered 17/2, 2010 at 7:17 Comment(5)
In line 2 of Bean class you have mentioned SomeElement and in the getter method u have mentioned SomeClass... Can u clarifyBuiltin
Sorry, it was just a typo. I've edited my post. Of course, I use the same kind of object (as you did not provide any code snippet, I made some assumptions concerning what you have in your JSF page and bean).Exhort
Hi i have attached the my code, but getting error.Can u Help.Builtin
@Hari I've edited my post. Please provide the stacktrace of your error if my advices do not solve your issue...Exhort
Thanks romaintaz i am not getting any error. But the added data is not reflecting on the screen, When i iterate the Item List i can see the added data in the console.Builtin

© 2022 - 2024 — McMap. All rights reserved.