7

I am trying to learn PF so I started with displaying datatable first and navigating to next page on rowClick passing parameters, but got stuck with the following error. I found similar problem for that question but no luck yet. I hope somebody will help me out.

I am getting following error:

DataModel must implement org.primefaces.model.SelectableDataModel when selection is enabled.

Caused by:
javax.faces.FacesException - DataModel must implement org.primefaces.model.SelectableDataModel when selection is enabled.

my Page:

 <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:p="http://primefaces.org/ui">

<h:head>
<title>Primefaces 3.1</title>

</h:head>
<h:body>
    <h:form id="form">          
            <p:dataTable value="#{tableBean.cars}" var="var" rowkey="#{var.model}" 
            selection="#{tableBean.car}" selectionMode="single">
            <p:column>  <f:facet name="header">
                                <h:outputText styleClass="outputText" value="Model"></h:outputText>
                            </f:facet>
                            <h:outputText styleClass="outputText"
                                value="#{var.model}"></h:outputText>
                        </p:column>
                        <p:column>
                            <f:facet name="header">
                                <h:outputText styleClass="outputText" value="Color"></h:outputText>
                            </f:facet>
                            <h:outputText styleClass="outputText"
                                value="#{var.randomColor}"></h:outputText>
                        </p:column></p:dataTable>                               
        </h:form>
</h:body>
</html>

my bean Classes:

@ManagedBean
@ViewScoped
public class TableBean extends ListDataModel<Car> implements SelectableDataModel<Car>{

    private List<Car> cars;
    private Car car;

    public List<Car> getCars() {

        cars = new ArrayList<Car>();
        Car car1 = new Car();
        car1.setModel("BMW");
        car1.setRandomColor("Black");
        cars.add(car1);
        Car car2 = new Car();       
        car2.setModel("Audi");
        car2.setRandomColor("White");
        cars.add(car2);

        return cars;
    }

    public String onRowSelect(){
        System.out.println("Row Click!!!");
        return "otherpage";//Does this nav works???if not how???
    }

    public Car getCar() {
        return car;
    }

    @Override
    public Car getRowData(String pArg0) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Object getRowKey(Car pArg0) {
        // TODO Auto-generated method stub
        return null;
    }   
    }

OtherBean:

public class Car{

    private String model;   
    private String randomColor; 

    public String getRandomColor() {
        return randomColor;
    }
    public void setRandomColor(String pRandomColor) {
        randomColor = pRandomColor;
    }

    public String getModel() {
        return model;
    }
    public void setModel(String pModel) {
        model = pModel;
    }

}
Catfish
  • 18,876
  • 54
  • 209
  • 353
user1226447
  • 153
  • 1
  • 5
  • 11

4 Answers4

28

The #{tableBean.cars} must implement SelectableDataModel if you don't specify the rowKey attribute on the <p:dataTable>.

You have however implemented it on the #{tableBean} instead. This is not right. You can find correct examples in the PrimeFaces showcase. Basically, your TableBean class must look like this according to the showcase code example:

@ManagedBean
@ViewScoped
public class TableBean implements Serializable {

    private List<Car> cars;
    private Car car;
    private CarDataModel carsModel;

    public TableBean() {
        cars = new ArrayList<Car>();
        // Populate cars here and thus NOT in the getter method!
        carsModel = new CarDataModel(cars);
    }

    // ...
}

Where the CarDataModel look like this (again, just copied from PrimeFaces showcase code example):

public class CarDataModel extends ListDataModel<Car> implements SelectableDataModel<Car> {  

    public CarDataModel() {
    }

    public CarDataModel(List<Car> data) {
        super(data);
    }

    @Override
    public Car getRowData(String rowKey) {
        List<Car> cars = (List<Car>) getWrappedData();

        for(Car car : cars) {
            if(car.getModel().equals(rowKey))
                return car;
        }

        return null;
    }

    @Override
    public Object getRowKey(Car car) {
        return car.getModel();
    }

}

Finally use #{tableBean.carsModel} instead of #{tableBean.cars} as value of <p:dataTable>. Exactly as in the showcase example.

<p:dataTable value="#{tableBean.carsModel}" var="car" ... />

Another, easier, way is to just specify the rowKey attribute on the <p:dataTable>.

<p:dataTable value="#{tableBean.cars}" var="car" rowKey="#{car.model}" ... />

This way you don't need the whole SelectableDataModel. You only need to ensure that it's never null and always unique across the rows. See also DataModel must implement org.primefaces.model.SelectableDataModel when selection is enabled, but I have already defined rowKey.

Cœur
  • 37,241
  • 25
  • 195
  • 267
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thanks for the comment, BalusC, I have couple of questions, what is the use of rowKey? Is it for the unique value for the column of the table being displayed? What if I have lets say 2 primary key in the same table. Another question is, What do you mean by if I use rowKey I dont have to implement CarDataModel, can you explain little bit...and also can you put some light on what selection attribute does in . – user1226447 May 10 '12 at 07:37
  • The `rowKey` basically tells PrimeFaces what the unique identifier is of the row. The `selection` basically tells PrimeFaces where it has to get/set the references of selected rows. The point of `SelectableDataModel` is to be able to identify unique rows based on other criteria than what is already available by the row object itself (for which you would need `rowKey`). – BalusC May 10 '12 at 16:56
  • What we do if there are 2 primary keys, what we do in such scenario? – user1226447 May 10 '12 at 17:16
  • Either use a composite key or create a `SelectableDataModel`. – BalusC May 10 '12 at 17:25
  • 4
    Note that you may still get the same error even though you may have defined a rowKey attribute **if** the said attribute returns null (e.g. it's not initialized). – Marcus Junius Brutus Oct 30 '12 at 07:26
  • For a unique object identity `rowKey="#{car.hashCode()}"` would be ok? Depends on your `hashCode()` and `equals()` implementation of course, but if not overwritten it is unique for each instance. – opfau Oct 07 '15 at 08:44
  • @opfau: hashcode doesn't per definition represent identity of the class' instance (multiple different instances can have same hashcode, you see, `int` has a hard limit in available values), but equals does (and does not force a limit anywhere). – BalusC Oct 07 '15 at 08:49
  • Indeed that's not a good idea even the `hashCode()` implementation depends on the JVM. – opfau Oct 07 '15 at 09:29
1

Ensure to set the rowKey parameter in the bean method that populates the "value=.." of the datatable. Mine returned this error because the rowKey was null.

0

It worked for my project using a composite key for rowkey e.g.: rowKey="#{course.getCompositeKey()

Since I didn't have a compositeKey variable I simply created one in my Course Class (in your case the Car Class). The 2 primary keys are strings so I just said this.compositeKey=this.courseNumber+this.product--you just use whatever 2 primary keys are in your Car class instead of courseNumber and product.

Armando Perea
  • 499
  • 2
  • 6
  • 18
0

Youd on't have to implement the datamodal in your managedbean, just specify in the proprety of the datatable the "rowkey" like this: rowkey="{mbean.atribute1}"
-- atribute1 must be diplayed in the data table column.

Must

Community
  • 1
  • 1
mkebri
  • 2,025
  • 1
  • 16
  • 14