addGeneratedColumn() - How to access this column?

Hi all,

I have a table generated from a database query with the fields “jobId”, “userId”, “submissionTime”, “status”. For this table I need a simple checkbox in each row for selecting the rows which a user wants to delete. The problem is I don’t get access to this checkbox (NPE in third code-block). I think it’s because the column select is not accessable. The example in
here
works properly for me, but I don’t know where am I using the ColumnGenerator (or the table settings) wrong. Just printing the columnId in the ColumnGenerator to the console gives me “select”, so I don’t really understand where is the problem?

Any help is appreciated! :slight_smile:


this.jobListTable = (Table) this.components.get("jobListTable");
this.jobListTable.setContainerDataSource(jobListContainer); // from SQLQueryContainer

this.jobListTable.addGeneratedColumn("select",
				new CheckBoxColumnGenerator());
		
this.jobListTable.setVisibleColumns(new Object[] { "select", "jobId",
		"userId", "submissionTime", "status" });
this.jobListTable.setColumnHeaders(new String[] { "", "Job Id",
		"User Id", "Submission Time", "Status" });

this.jobListTable.sort(new Object[] { "submissionTime" },
		new boolean[] { false });

addComponent(this.jobListTable);

class CheckBoxColumnGenerator implements Table.ColumnGenerator {

		@Override
		public Component generateCell(Table source, Object itemId,
				Object columnId) {
			Property prop = source.getItem(itemId).getItemProperty("jobId"); // if using getItemProperty(columnId) here instead of this the prop will be null

			return new CheckBox(null, prop);
		}
	}

class DeleteListener implements Button.ClickListener {
		@Override
		public void buttonClick(ClickEvent event) {

			List<Object> toDelete = new ArrayList<Object>();

			for (Object id : jobListTable.getItemIds()) {
				CheckBox checkBox;
				try {
					checkBox = (CheckBox) jobListTable.getContainerProperty(id,
							"select").getValue();
				} catch (Exception e) {
					e.printStackTrace(); // ->> NullPointerException
				}
			}
		}
	}

Cheers,
Benny

When generating a column, it is generated to Table only and not to the data container, so it doesn’t have a property. The columnId is the one you have set for the column i.e. “select” so the generateCell will be called for the “select” columnId.

Property prop = source.getItem(itemId).getItemProperty("jobId"); // works
Property prop = source.getItem(itemId).getItemProperty(columnId); // doesn't work (columnId equals "select") 

As a side note, Is the Property given in return new CheckBox(null, prop); a boolean type? Name wouldn’t suggest that so perhaps you have an error there.

I would keep track of the row states somewhere outside of the Table, since now when you scroll the table and cause the columns to be regenerated, the checkbox states are lost.

Hi Johannes,

thanks for your answer. :slight_smile:

Is there really no way for the this simple task while using a SQLContainer? I think checkboxes for deleting table rows is nothing special and for a normal table (filled with addItem) it works properly, even the checkboxes keep their states while sorting. I can’t understand at the moment why this will not work with the “virtual” column. Is there no possiblity to connect the single checkboxes with their row?

Cheers
Benny

Hi,

Here’s a generic way of using a generated checkbox to keep track of selected items in a table. It’ll work with SQLContainer, and any other container for that matter.

HTH,
Cheers,
Charles


final Table table = new Table();
    table.setSizeUndefined();

    /* Define the names and data types of columns.
     * The "default value" parameter is meaningless here. */
    table.addContainerProperty("First Name", String.class,  null);
    table.addContainerProperty("Last Name",  String.class,  null);
    table.addContainerProperty("Year",       Integer.class, null);

    /* Add a few items in the table. */
    table.addItem(new Object[] {"Nicolaus","Copernicus", 1473}, 1);
    table.addItem(new Object[] {"Tycho",   "Brahe", 1546}, 2);
    table.addItem(new Object[] {"Giordano","Bruno", 1548}, 3);
    table.addItem(new Object[] {"Galileo", "Galilei", 1564}, 4);
    table.addItem(new Object[] {"Johannes","Kepler", 1571}, 5);
    table.addItem(new Object[] {"Isaac",   "Newton", 1643}, 6);

    /* This set contains the ids of the "selected" items */
    final Set<Object> selectedItemIds = new HashSet<Object>();
    selectedItemIds.add(4); // We'll start off with #4 selected, just to show that it works

    /* This checkbox reflects the contents of the selectedItemIds set */ 
    table.addGeneratedColumn("selected", new Table.ColumnGenerator() {
      @Override
      public Object generateCell(Table source, final Object itemId, Object columnId) {
        boolean selected = selectedItemIds.contains(itemId);
        /* When the chekboc value changes, add/remove the itemId from the selectedItemIds set */
        final CheckBox cb = new CheckBox("", selected);
        cb.addListener(new Property.ValueChangeListener() {
          @Override
          public void valueChange(Property.ValueChangeEvent event) {
            if(selectedItemIds.contains(itemId)){
              selectedItemIds.remove(itemId);
            } else {
              selectedItemIds.add(itemId);
            }
          }
        });
        return cb;
      }
    });
    /* Just some cosmetics : no caption for the checkboc, and make it the first column */ 
    table.setColumnHeader("selected", "");
    table.setVisibleColumns(new String[]{"selected", "First Name", "Last Name", "Year"});
    layout.addComponent(table);
    
    /* Just a demo of how to use the selected items set */
    layout.addComponent(new Button("Delete", new Button.ClickListener() {
      @Override
      public void buttonClick(Button.ClickEvent event) {
        // Here, you'd do whatever it is you want to do : I'm just removing then from the table
        for (Object itemId : selectedItemIds) {
          table.removeItem(itemId);
        }
      }
    }));

Hi Charles,

many thanks for that! :slight_smile:

Cheers,
Benny

I am wondering how I can implement ‘Select All’ button Into Charles’s example above.

How can I get access to the check box component for the column “selected”?
When user click ‘Select All’ button, I want to set “selected” check box to true for all items.

Thanks for the help in advance…


Hello Everybody

I have same problem. But little different.

I use Generate Column. The column contains checkbox.

  1. I want to select row to mapping checkbox is checked.
    I used

    table.addListener(new ValueChangeListener())

    because this listener can currently selected items getting.
    I not use

    table.addItemClickListener(new ItemClickListener())

    because this listener can’t currently selected items. Getting Before selected items
  2. I want to checkbox checking and unchecking to table selected row affecting…
    I used

    checkbox.addListener(new ValueChangeListener())

    because this listener is only one useful.

BUT. That 2 listener recursive method???

I think solution is



  1. table.addItemClickListener(new ItemClickListener()){




    table.getValue();

    // TO BE CURRENTLY selected Items


    });


    2.

    checkbox.addClickListener(new ClickListener())

    // TO HAVE click listener

How can I do?

Using Vaadin 7.

Sorry - I’m afraid I don’t understand the question that you are asking.

I think you might be asking - how do I create a checkbox column that reflects the table’s selected status? Is that right?

That is right and I can.

check box listener can do table row selection. reverse table row selection listener can do check box checking

But this listeners not working with. Because listeners are both ValueChangeListener

Just How can I mouse click listener on CheckBox?

Simply put? You can’t - at least, not with the core Vaadin CheckBox component - you can only listen for Value Change.

Okey. Then

how can I get currently Selected Items in

table.addItemClickListener(new ItemClickListener(..){ // table.getValue() is not currently }); like

table.addListener(new ValueChangeListener(..){ table.getValue(); //is currently items }); ?

I’m afraid I still don’t understand what you’re asking.

If you want to know when the selection on a table changes, you must use a ValueListener.
If you want to know when the value of a checkbox changes, you must use a ValueListener.

If you want to stop recursion between those two things, I think that you probably need to use a boolean flag.

If I get some time, I will try and implement an example, based on my understanding of what you are trying to do…

I think you are trying to have a checkbox column that reflects the selection value of the table (as opposed my selectedIds set in my example from 1 year ago). Selecting a row via a normal selection should set/unset the chechbox. Setting/unsetting the checkbox should change the row selection.

Is that what you are trying to do?

My code is

protected void init(VaadinRequest request) {

        VerticalLayout mainLayout = new VerticalLayout();
        mainLayout.setMargin(new MarginInfo(true, false, false, false));
        mainLayout.setSizeFull();

        final Table table = new Table();
        table.setSizeFull();

        table.setSelectable(true);
        table.setImmediate(true);
        table.setMultiSelect(true);

        // table.setRowHeaderMode(RowHeaderMode.INDEX);

        table.setColumnCollapsingAllowed(true);

        table.setColumnReorderingAllowed(true);

        JPAContainer<Test> dbTable = JPAContainerFactory.make(Test.class, "TableCheck");

        table.setContainerDataSource(dbTable);

        table.addGeneratedColumn("check", new ColumnGenerator() {

            @Override
            public Component generateCell(final Table source, final Object itemId, Object columnId) {

                final CheckBox checkBox = new CheckBox("", false);
                checkBox.addValueChangeListener(new ValueChangeListener() {
                     @Override
                     public void valueChange(com.vaadin.data.Property.ValueChangeEvent event) {
                        if ((Boolean) event.getProperty().getValue() == true) {
                            source.select(itemId); // table selecting row
                            System.out.println("SELECT");
                        } else {
                            source.unselect(itemId); // // table unselecting row
                            System.out.println("UN SELECT");
                        }
                        System.out.println("ITEM ID: " + itemId);
                    }
                });
                return checkBox;
            }

        });

        table.addItemClickListener(new ItemClickListener() {
            @Override
            public void itemClick(ItemClickEvent event) {
                CSTestTable tt = (CSTestTable) event.getSource();
                System.out.println(tt.getValue()); // this selected value is not currently, before values
            }
        });

        table.addListener(new Property.ValueChangeListener() {
            public void valueChange(ValueChangeEvent event) {
                System.out.println(table.getValue()); 
                
                Collection<Object> ids = (Collection<Object>) table.getItemIds();
                
                
                //clear checks
                for (Object id : ids) {
                    CheckBox ch = (CheckBox) table.getItem(id).getItemProperty("check");

                    ch.setValue(false);
                }

                Set selected = (Set) table.getValue(); // selected values
                // checking all selected items
                for (final Iterator it = selected.iterator(); it.hasNext();) {
                    Object id = it.next();
                    System.out.println("ID: " + id);

                    CheckBox ch = (CheckBox) table.getColumnGenerator("check");
                    ch.setValue(true);
                    System.out.println("VALUE: " + ch.getValue());
                }
            }
        });

        mainLayout.addComponent(table);
        mainLayout.setExpandRatio(table, 1);
        table.setVisibleColumns((Object[]) new String[]
 { "check", "name", "id"/* , "state", "date", "validated", "checked" */});

        setContent(mainLayout);
    }

I want set value in checkbox when selected row. // table value listener
I want select row in table when checked of checkbox // checkbox value listener

These listener’s working severally.

How to use these listener’s that both?

Do you really want to do this? Because it’s really quite tricky - and I’ve spent too much time on it already!

CheckBox ch = (CheckBox) table.getItem(id).getItemProperty("check");

As a start - this won’t work : “check” is a generated column, not an item property. You’ll have to keep track of all of your itemId->checkbox yourself.

OK; I’ve changed the example above : the checkboxes now reflect the tables selection status, and vice versa. Toggling the checkbox changes the table’s value and changing the table value updates the checkboxes.The inifinte loop is avoided by a simple boolean flag, and the checkboxes are kept track of by attach/detach listeners.

See the code as a
gist on GitHub

Cheers,

Charles.

Thank you very much.

Charles Anthony

How to do that on Vaadin 6.7?
We do not have AttachListener…

Hi,

I have a issue related to generated column. I add a checkbox in each row of table. Table contains huge amount of data. Some of checkboxs is selected. when I click on header on that column. The column is not getting sorted like it woluld be all the checked checkboxs comes to gether.
Please give me some solution of this problem.

Thanks,
Avdhesh