3

I am working on product development using Vaadin. Till date we are using Vaadin 7.

We need to display data on tabular form as well as chart in based on rule. Also user can modify the rule any time from configuration option. so can not define bean with fix number of variables.

In Vaadin 7, using container we can create empty container object and add column run time. But in Vaadin 8 does not allowing as per my knowledge.

With 7 compatible package, it will work for 7 grid.

Example in scala i was creating container from dataframe

def getcontainer(dataframe: Dataset[Row]): IndexedContainer = {

    var container = new IndexedContainer();
/*get number column need to create in data frame. it will be change on evertime based on output dataframe.*/
    val columns = dataframe.columns

    for (x <- columns) {
      try {
        container.addContainerProperty(x, classOf[Any], "");
      } catch {
        case e: NullPointerException =>
          e.printStackTrace()
          println("Column name must not be null")
        case e: Exception =>
          e.printStackTrace()
          println("Some went wrong with dataframe")

      }
    }
return container
}

So how can i do same thing in Vaadin 8?

Any help will be appreciated.

Uttam Kasundara
  • 237
  • 3
  • 13
  • Please add a [sscce](http://sscce.org) so we can understand better how your _dynamic_ beans/objects look like and how they can change. It's ok even if it's based on your working implementation with the compatibility package. The important thing is to be able to figure out what you need, because the description so far presents too little information to work with. – Morfic Aug 02 '17 at 06:46
  • For example, I've suggested [this answer](https://stackoverflow.com/a/43120904/474287) using a sort of adapter for his original bean, to someone who was trying to _reverse_ the grid. So it should be possible to display data with a variable number of columns, but we need to understand what it looks like and how it changes. – Morfic Aug 02 '17 at 06:56
  • I agree Morfic, we need more information to help you. However, it feels like you need a bean that has a Map which maps a column to its value. Using such a bean, you need to call `grid.addColumn` as specified in your configuration option. The column value could be calculated by a simple `Map.get` call. – Steffen Harbich Aug 02 '17 at 08:34
  • By the way, you can use the [Vaadin 7 compatibility layer](https://vaadin.com/docs/-/part/framework/migration/migrating-to-vaadin8.html) to bring your app virtually as-is to Vaadin 8, continuing to use the previous data-model. – Basil Bourque Aug 03 '17 at 19:48

1 Answers1

6

You can add columns to a grid using the addColumn(propertyName) or addColumn(ValueProvider, ...) method variations.

I'm not familiar with spark-data source, so I'm not sure what exactly the Row object is. If it's a runtime generated object with the property names you get from the dataset columns then the first method should be a direct replacement. If the Row is similar to a key-value data structure (such as a map) then you can use the second method.

For this exercise I'm going to simulate the Row in java as a key-value data structure using a HashMap.

Let me know if I'm missing something.

import com.vaadin.ui.Button;
import com.vaadin.ui.Grid;
import com.vaadin.ui.VerticalLayout;

import java.time.LocalDate;
import java.util.List;
import java.util.ArrayList;
import java.util.Random;
import java.util.Set;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
import java.util.stream.Collectors;

public class GridWithMapObjects extends VerticalLayout {
    // data to use in random generations
    private static final Random RANDOM = new Random();
    private static final String[] NAMES = {"Alex", "Jay", "John", "Mary", "Joan", "Corrine"};
    private static final String[] SURNNAMES = {"Carlisle", "Dunn", "Albert", "Crow", "Picket", "Valden"};
    private static final String[] NICKNAMES = {"The one", "The second", "The third", "The fourth", "The fifth", "The sixth"};
    private static final String[] NATIONALITIES = {"American", "Algerian", "Italian", "Japanese", "Australian", "Romanian"};
    private static final LocalDate[] BIRTYHDAYS = {LocalDate.parse("1970-01-01"), LocalDate.parse("1980-08-15"), LocalDate.parse("1990-05-02"), LocalDate.parse("2000-10-26"), LocalDate.parse("2010-06-06"), LocalDate.parse("2015-12-12")};

    public GridWithMapObjects() {
        // basic setup
        Grid<Row> grid = new Grid<>();
        regen(grid);
        addComponents(grid, new Button("Regen grid", event -> regen(grid)));
    }

    // utility method to regenerate grid columns and data
    private void regen(Grid<Row> grid) {
        // generate some random data
        DataSet dataSet = generateRandomDataSet();

        // setup columns
        grid.removeAllColumns();
        for (String column : dataSet.getColumns()) {
            grid.addColumn(row -> row.getValue(column)).setCaption(column);
        }

        // add items
        grid.setItems(dataSet.getRows());
    }

    // utility method to generate some random data
    private DataSet generateRandomDataSet() {
        // randomly select some columns
        int numberOfColumns = RANDOM.nextInt(ColumnGenerator.values().length) + 1;
        Set<ColumnGenerator> generators = new HashSet<>(numberOfColumns);
        while (generators.size() < numberOfColumns) {
            generators.add(ColumnGenerator.values()[RANDOM.nextInt(ColumnGenerator.values().length)]);
        }

        // randomly generate rows with the selected columns
        List<Row> rows = new ArrayList<>();
        for (int i = 0; i < RANDOM.nextInt(10) + 1; i++) {
            Row row = new Row();
            for (ColumnGenerator generator : generators) {
                row.setValue(generator.name(), generator.randomize());
            }
            rows.add(row);
        }

        return new DataSet(generators.stream().map(Enum::name).collect(Collectors.toList()), rows);
    }

    // column generator
    private enum ColumnGenerator {
        DATE_OF_BIRTH {
            @Override
            public Object randomize() {
                return BIRTYHDAYS[RANDOM.nextInt(BIRTYHDAYS.length)];
            }
        },
        NAME {
            @Override
            public Object randomize() {
                return NAMES[RANDOM.nextInt(NAMES.length)];
            }
        },
        SURNAME {
            @Override
            public Object randomize() {
                return SURNNAMES[RANDOM.nextInt(SURNNAMES.length)];
            }
        },
        NICK_NAME {
            @Override
            public Object randomize() {
                return NICKNAMES[RANDOM.nextInt(NICKNAMES.length)];
            }
        },
        SEX {
            @Override
            public Object randomize() {
                return RANDOM.nextBoolean() ? "F" : "M";
            }
        },
        NATIONALITY {
            @Override
            public Object randomize() {
                return NATIONALITIES[RANDOM.nextInt(NATIONALITIES.length)];
            }
        },
        STATUS {
            @Override
            public Object randomize() {
                return RANDOM.nextBoolean() ? "ONLINE" : "OFFLINE";
            }
        },
        LICENSE_ACTIVE {
            @Override
            public Object randomize() {
                return RANDOM.nextBoolean();
            }
        },
        REPUTATION {
            @Override
            public Object randomize() {
                return RANDOM.nextInt(1000);
            }
        };

        public abstract Object randomize();

    }

    // simulation of data set object
    public class DataSet {
        private List<String> columns;
        private List<Row> rows;

        public DataSet(List<String> columns, List<Row> rows) {
            this.columns = columns;
            this.rows = rows;
        }

        public List<String> getColumns() {
            return columns;
        }

        public List<Row> getRows() {
            return rows;
        }
    }

    // simulation of row object
    public class Row {
        private Map<String, Object> values = new HashMap<>();

        public Object getValue(String column) {
            return values.get(column);
        }

        public void setValue(String column, Object value) {
            values.put(column, value);
        }
    }
}

Result:

Grid dynamic columns

Morfic
  • 15,178
  • 3
  • 51
  • 61
  • I wish there is simple snippet instead of this 90% irrelevant code – Martin Ma Oct 18 '22 at 18:05
  • @MartinMa I'm sorry if the above code, that you can directly copy-paste to get a working example and which you can use to learn how things work, offends you. If you have a moment to spare, please feel free to share your own simplified & improved version. – Morfic Oct 18 '22 at 18:48