7

I have this JSF table. I want to add row numbers.

<?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:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      >
    <h:head>
        <h:outputStylesheet library="css" name="table-style.css"  />
    </h:head>
    <h:body>

        <h1>JSF 2 dataTable example</h1>
        <h:form>
            <h:dataTable value="#{order.orderList}" var="o"
                styleClass="order-table"
                headerClass="order-table-header"
                rowClasses="order-table-odd-row,order-table-even-row"
            >
                        <h:column>

                    <f:facet name="header">No</f:facet>

                    <h:inputText value="#{order.orderList.rowIndex + 1}" size="10" rendered="false" />

                    <h:outputText value="#{order.orderList.rowIndex + 1}" rendered="#{not order.orderList.rowIndex + 1}" />

                </h:column>
                <h:column>

                    <f:facet name="header">Order No</f:facet>

                    <h:inputText value="#{o.orderNo}" size="10" rendered="#{o.editable}" />

                    <h:outputText value="#{o.orderNo}" rendered="#{not o.editable}" />

                </h:column>

                <h:column>

                    <f:facet name="header">Product Name</f:facet>

                    <h:inputText value="#{o.productName}" size="20" rendered="#{o.editable}" />

                    <h:outputText value="#{o.productName}" rendered="#{not o.editable}" />

                </h:column>

                <h:column>

                    <f:facet name="header">Price</f:facet>

                    <h:inputText value="#{o.price}" size="10" rendered="#{o.editable}" />

                    <h:outputText value="#{o.price}" rendered="#{not o.editable}" />

                </h:column>

                <h:column>

                    <f:facet name="header">Quantity</f:facet>

                    <h:inputText value="#{o.qty}" size="5" rendered="#{o.editable}" />

                    <h:outputText value="#{o.qty}" rendered="#{not o.editable}" />

                </h:column>

                <h:column>

                    <f:facet name="header">Action</f:facet>

                    <h:commandLink value="Edit" action="#{order.editAction(o)}" rendered="#{not o.editable}" />

                </h:column>

            </h:dataTable>

            <h:commandButton value="Save Changes" action="#{order.saveAction}" />

        </h:form>
    </h:body>

</html>


package com.mkyong;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean(name="order")
@SessionScoped
public class OrderBean implements Serializable{

    private static final long serialVersionUID = 1L;

    private static final ArrayList<Order> orderList = 
        new ArrayList<Order>(Arrays.asList(

        new Order("A0001", "Intel CPU", 
                new BigDecimal("700.00"), 1),
        new Order("A0002", "Harddisk 10TB", 
                new BigDecimal("500.00"), 2),
        new Order("A0003", "Dell Laptop", 
                new BigDecimal("11600.00"), 8),
        new Order("A0004", "Samsung LCD", 
                new BigDecimal("5200.00"), 3),
        new Order("A0005", "A4Tech Mouse", 
                new BigDecimal("100.00"), 10)
    ));

    public ArrayList<Order> getOrderList() {

        return orderList;

    }

    public String saveAction() {

        //get all existing value but set "editable" to false 
        for (Order order : orderList){
            order.setEditable(false);
        }

        //return to current page
        return null;

    }

    public String editAction(Order order) {

        order.setEditable(true);
        return null;
    }

    public static class Order{

        String orderNo;
        String productName;
        BigDecimal price;
        int qty;
        boolean editable;

        public Order(String orderNo, String productName, BigDecimal price, int qty) {
            this.orderNo = orderNo;
            this.productName = productName;
            this.price = price;
            this.qty = qty;
        }

        public boolean isEditable() {
            return editable;
        }
        public void setEditable(boolean editable) {
            this.editable = editable;
        }
        public String getOrderNo() {
            return orderNo;
        }
        public void setOrderNo(String orderNo) {
            this.orderNo = orderNo;
        }
        public String getProductName() {
            return productName;
        }
        public void setProductName(String productName) {
            this.productName = productName;
        }
        public BigDecimal getPrice() {
            return price;
        }
        public void setPrice(BigDecimal price) {
            this.price = price;
        }
        public int getQty() {
            return qty;
        }
        public void setQty(int qty) {
            this.qty = qty;
        }
    }
}

I added #{order.orderList.rowIndex + 1} in order to count the rows and display the number. But when I run the JSF page I get this error:

java.lang.NumberFormatException: For input string: "rowIndex"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:481)
    at java.lang.Integer.parseInt(Integer.java:514)
    at javax.el.ListELResolver.toInteger(ListELResolver.java:409)
    at javax.el.ListELResolver.getValue(ListELResolver.java:202)
    at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:176)
    at com.sun.faces.el.DemuxCompositeELResolver.getValue(DemuxCompositeELResolver.java:203)
    at com.sun.el.parser.AstValue.getValue(AstValue.java:138)
    at com.sun.el.parser.AstValue.getValue(AstValue.java:183)
    at com.sun.el.parser.AstNot.getValue(AstNot.java:63)
    at com.sun.el.parser.AstPlus.getValue(AstPlus.java:59)
    at com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:224)
    at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:109)
    at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:194)
    at javax.faces.component.UIComponentBase.isRendered(UIComponentBase.java:413)
    at javax.faces.component.UIData.iterate(UIData.java:1993)
    at javax.faces.component.UIData.processDecodes(UIData.java:1161)
    at javax.faces.component.UIForm.processDecodes(UIForm.java:225)
    at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1176)
    at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1176)
    at javax.faces.component.UIViewRoot.processDecodes(UIViewRoot.java:933)
    at com.sun.faces.lifecycle.ApplyRequestValuesPhase.execute(ApplyRequestValuesPhase.java:78)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1542)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:849)
    at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:746)
    at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1045)
    at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:228)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    at java.lang.Thread.run(Thread.java:679)

I think that rowIndex is not found. How I can fix this?

Regards

Matt Handy
  • 29,855
  • 2
  • 89
  • 112
Peter Penzov
  • 1,126
  • 134
  • 430
  • 808

2 Answers2

17

The rowIndex is a property of <h:dataTable> component itself, not of its java.util.List value.

<h:dataTable binding="#{table}" ...>
    <h:column>#{table.rowIndex + 1}</h:column>
    ...
</h:dataTable>

The exception which you got is basically telling that you're attempting to access a List item by a string index like so orderList.get("rowIndex"), this is not valid. The only valid way to access a list item is using the brace notation like so #{order.orderList[0]} which resolves to orderList.get(0), but this is not what you need, after all.

An alternative is to wrap the orderList in a DataModel property and provide that as value instead, e.g.

<h:dataTable value="#{order.orderModel}" ...>
    <h:column>#{order.orderModel.rowIndex + 1}</h:column>
    ...
</h:dataTable>

with

private transient DataModel orderModel;

public DataModel getOrderModel() {
    if (orderModel == null) {
        orderModel = new ListDataModel(orderList);
    }
    return orderModel;
}

It should be displayed for output only. It makes no sense to display it in an input component as it's not possible to set a sum as a single value expression. Also using it in the rendered attribute the way as you did is not valid as it doesn't return a boolean, but a long.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • do you know better example of datatable. The one that I have is not very good and I found this: http://balusc.blogspot.com/2006/06/using-datatables.html It's just what I need but it's for JSF 1.2. Is there a modern version? – Peter Penzov Mar 30 '12 at 21:10
  • 1
    Read the "notice" section in top. – BalusC Mar 30 '12 at 21:36
  • Yes I opened the example for JSF 2.0 but I get error when I import the code into Netbeans at this line: private Item item = new Item(); Is there a complete source code of the example? – Peter Penzov Mar 30 '12 at 21:47
  • Just create one? See also the article's text. This has all nothing to do with your initial problem by the way. If you have a new question, please ask a new question. – BalusC Mar 30 '12 at 21:52
4

Another option is use List's indexOf() method:

<h:outputText value="#{order.orderList.indexOf(o) + 1}"/>
andbi
  • 4,426
  • 5
  • 45
  • 70
  • 1
    Note that this requires EL 2.2. Further, a lookup of item's own index in the parent list everytime slows down rendering performance in case of large lists and complex objects. – BalusC Mar 30 '12 at 20:52