'preselection' on datatable in multiple selectionMode

UI Components for JSF
Post Reply
esteevens
Posts: 10
Joined: 18 Oct 2010, 21:05

21 Nov 2010, 21:03

Hello,

I'm using Netbeans 6.9 / Glassfish 3.0.1 / Mojarra 2.0.2 (FCS b10) / PrimeFaces 2.2RC2-SNAPSHOT (20/11/2010) / Google Chrome 9.0.587.0.

I'm trying to do a 'preselection' on a dataTable with multiple selectionMode with checkboxes. If I fill the selections array then only the selections on the first datatable page are retained...

Some code to make it clearer. It is basically the code from the showcase example. I only added the <html>, <h:head>, <h:body> tags and removed the radiobutton selection example code.

Code: Select all

<?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:p="http://primefaces.prime.com.tr/ui">

<h:head>
    <title>PrimefacesTest</title>
    <link type="text/css" rel="stylesheet" href="resources/skins/redmond/skin.css" />
</h:head>
<h:body>
<f:view contentType="text/html">

<h:form prependId="false">

    <p:dataTable var="car" value="#{tableBean2.cars}" paginator="true" rows="10"
                 selection="#{tableBean2.selectedCars}">

        <f:facet name="header">
            Checkbox Based Selection
        </f:facet>

        <p:column selectionMode="multiple" />

        <p:column headerText="Model">
            <h:outputText value="#{car.model}" />
        </p:column>

        <p:column headerText="Year">
            <h:outputText value="#{car.year}" />
        </p:column>

        <p:column headerText="Manufacturer">
            <h:outputText value="#{car.manufacturer}" />
        </p:column>

        <p:column headerText="Color">
            <h:outputText value="#{car.color}" />
        </p:column>

        <f:facet name="footer">
            <p:commandButton value="View" image="ui-icon ui-icon-search"
                             update="displayMulti" oncomplete="multiCarDialog.show()"/>
        </f:facet>
    </p:dataTable>

    <p:dialog header="Car Detail" widgetVar="multiCarDialog"
              width="250" height="300" showEffect="explode" hideEffect="explode">

        <p:dataList id="displayMulti"
                value="#{tableBean2.selectedCars}" var="selectedCar">
            Model: #{selectedCar.model}, Year: #{selectedCar.year}
        </p:dataList>

    </p:dialog>

</h:form>
                    
</f:view>
</h:body>
</html>
This is my java code. It is basically the code from the showcase example. I only added the ManagedBean, ViewScoped annotations and in the constructor I have put car[0] and car[10] in the selectedCars array.

Code: Select all

package org.primefaces.examples.view;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

import org.primefaces.examples.domain.Car;

@ManagedBean(name="tableBean2")
@ViewScoped
public class TableBean2 implements Serializable {

   private final static String[] colors;

   private final static String[] manufacturers;

   static {
      colors = new String[10];
      colors[0] = "Black";
      colors[1] = "White";
      colors[2] = "Green";
      colors[3] = "Red";
      colors[4] = "Blue";
      colors[5] = "Orange";
      colors[6] = "Silver";
      colors[7] = "Yellow";
      colors[8] = "Brown";
      colors[9] = "Maroon";

      manufacturers = new String[10];
      manufacturers[0] = "Mercedes";
      manufacturers[1] = "BMW";
      manufacturers[2] = "Volvo";
      manufacturers[3] = "Audi";
      manufacturers[4] = "Renault";
      manufacturers[5] = "Opel";
      manufacturers[6] = "Volkswagen";
      manufacturers[7] = "Chrysler";
      manufacturers[8] = "Ferrari";
      manufacturers[9] = "Ford";
   }

   private List<Car> cars;

   private Car selectedCar;

   private Car[] selectedCars;

   public TableBean2() {
      cars = new ArrayList<Car>();

      populateRandomCars(cars, 50);

      selectedCars = new Car[2];
      selectedCars[0] = cars.get(0);
      selectedCars[1] = cars.get(10);
   }

   public Car[] getSelectedCars() {
      return selectedCars;
   }
   public void setSelectedCars(Car[] selectedCars) {
      this.selectedCars = selectedCars;
   }

   public Car getSelectedCar() {
      return selectedCar;
   }

   public void setSelectedCar(Car selectedCar) {
      this.selectedCar = selectedCar;
   }

   private void populateRandomCars(List<Car> list, int size) {
      for(int i = 0 ; i < size ; i++)
         list.add(new Car(getRandomModel(), getRandomYear(), getRandomManufacturer(), getRandomColor()));
   }

   public List<Car> getCars() {
      return cars;
   }

   private int getRandomYear() {
      return (int) (Math.random() * 50 + 1960);
   }

   private String getRandomColor() {
      return colors[(int) (Math.random() * 10)];
   }

   private String getRandomManufacturer() {
      return manufacturers[(int) (Math.random() * 10)];
   }

   private String getRandomModel() {
      return UUID.randomUUID().toString().substring(0, 8);
   }
}
So I would expect to see a selection for the first car on the first datatable page and the first car on the second page. But when I switch to the second datatable page, the setSelectedCars method is called with only the first car from the first datatable page. This causes the selection to be overwritten...

Image
Image

Any suggestions on how to fix this or work around this?

Eddy

esteevens
Posts: 10
Joined: 18 Oct 2010, 21:05

23 Nov 2010, 12:50

It looks as if the initial selection (a.k.a preselection) is not completely passed on to the html page when the page is displayed at first.

As far as I can tell it goes this way:
1. In the java code I select item 0 and 10.
2. In the HTML only item 0 is in the hidden xxx_selection input field.
3. When switching to another datatable page only item 0 is POSTed back to the server.

This means that we effectively lost item 10 from the selection :?

esteevens
Posts: 10
Joined: 18 Oct 2010, 21:05

27 Nov 2010, 13:40

OK, apparently I'm the only one with this problem. I've worked around it by adding a preRenderComponent event to the p:dataTable. In the eventhandler I do the proper selection by calling addSelectedRowIndex. This is working. Note that I did not test it with lazy loading or so.

Code: Select all

<?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:p="http://primefaces.prime.com.tr/ui"
      xmlns:ui="http://java.sun.com/jsf/facelets">

    <h:head>
        <title>PrimefacesTest</title>
        <link type="text/css" rel="stylesheet" href="resources/skins/redmond/skin.css" />
    </h:head>

    <h:body>
        <f:view contentType="text/html">
             <h:form prependId="false">

                <p:dataTable id="table" var="car" value="#{tableBean2.cars}" paginator="true" rows="10"
                    selection="#{tableBean2.selectedCars}">
                    <f:event type="preRenderComponent" listener="#{tableBean2.preselect}"/>

                    <f:facet name="header">
                        Checkbox Based Selection
                    </f:facet>

                    <p:column selectionMode="multiple" />

                    <p:column headerText="Model">
                        <h:outputText value="#{car.model}" />
                    </p:column>

                    <p:column headerText="Year">
                        <h:outputText value="#{car.year}" />
                    </p:column>

                    <p:column headerText="Manufacturer">
                        <h:outputText value="#{car.manufacturer}" />
                    </p:column>

                    <p:column headerText="Color">
                        <h:outputText value="#{car.color}" />
                    </p:column>

                    <f:facet name="footer">
                        <p:commandButton value="View" image="ui-icon ui-icon-search" update="displayMulti" oncomplete="multiCarDialog.show()"/>
                    </f:facet>
                </p:dataTable>

                <p:dialog header="Car Detail" widgetVar="multiCarDialog"
                          width="250" height="300" showEffect="explode" hideEffect="explode">
                    <p:dataList id="displayMulti"
                            value="#{tableBean2.selectedCars}" var="selectedCar">
                        Model: #{selectedCar.model}, Year: #{selectedCar.year}
                    </p:dataList>
                </p:dialog>


             </h:form>
        </f:view>
    </h:body>
</html>

Code: Select all

package org.primefaces.examples.view;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ComponentSystemEvent;
import org.primefaces.component.datatable.DataTable;
import org.primefaces.examples.domain.Car;

@ManagedBean(name="tableBean2")
@ViewScoped
public class TableBean2 implements Serializable {

	private final static String[] colors;

	private final static String[] manufacturers;

	static {
		colors = new String[10];
		colors[0] = "Black";
		colors[1] = "White";
		colors[2] = "Green";
		colors[3] = "Red";
		colors[4] = "Blue";
		colors[5] = "Orange";
		colors[6] = "Silver";
		colors[7] = "Yellow";
		colors[8] = "Brown";
		colors[9] = "Maroon";

		manufacturers = new String[10];
		manufacturers[0] = "Mercedes";
		manufacturers[1] = "BMW";
		manufacturers[2] = "Volvo";
		manufacturers[3] = "Audi";
		manufacturers[4] = "Renault";
		manufacturers[5] = "Opel";
		manufacturers[6] = "Volkswagen";
		manufacturers[7] = "Chrysler";
		manufacturers[8] = "Ferrari";
		manufacturers[9] = "Ford";
	}


	private List<Car> cars;

	private Car selectedCar;

	private Car[] selectedCars;

	public TableBean2() {

		cars = new ArrayList<Car>();
		populateRandomCars(cars, 51);

                selectedCars = new Car[3];
                selectedCars[0] = cars.get(0);
                selectedCars[1] = cars.get(10);
                selectedCars[2] = cars.get(20);
	}

        public void preselect(ComponentSystemEvent cse)
        {
            doPreselection((DataTable)cse.getComponent(), Arrays.asList(selectedCars));
        }

        private void doPreselection(DataTable dt, List selection)
        {
            Object value = dt.getValue();
            if (value instanceof List)
            {
                List list = (List) value;
                for (int i = 0; i < list.size(); i++)
                {
                    if (selection.contains(list.get(i)))
                    {
                        dt.addSelectedRowIndex(i);
                    }
                }
            }
        }

        public Car[] getSelectedCars() {
		return selectedCars;
	}

	public void setSelectedCars(Car[] selectedCars) {
		this.selectedCars = selectedCars;
	}

	public Car getSelectedCar() {
		return selectedCar;
	}

	public void setSelectedCar(Car selectedCar) {
		this.selectedCar = selectedCar;
	}

	private void populateRandomCars(List<Car> list, int size) {
		for(int i = 0 ; i < size ; i++)
			list.add(new Car(getRandomModel(), getRandomYear(), getRandomManufacturer(), getRandomColor()));
	}

	public List<Car> getCars() {
		return cars;
	}

	private int getRandomYear() {
		return (int) (Math.random() * 50 + 1960);
	}

	private String getRandomColor() {
		return colors[(int) (Math.random() * 10)];
	}

	private String getRandomManufacturer() {
		return manufacturers[(int) (Math.random() * 10)];
	}

	private String getRandomModel() {
		return UUID.randomUUID().toString().substring(0, 8);
	}
}

pdxhondo
Posts: 1
Joined: 16 Feb 2017, 18:18

09 Jun 2018, 01:06

You're not the only person with this problem (even after eight years). Looks like the selection list is initially cleared before the first time the table is rendered. Thanks for the solution to use the "preRenderComponent" listener.

sutil
Posts: 1
Joined: 12 Jul 2018, 21:27

12 Jul 2018, 21:30

Implement the equals() method in your Car class.

Post Reply

Return to “PrimeFaces”

  • Information
  • Who is online

    Users browsing this forum: No registered users and 45 guests