Калитка с переменным количеством столбцов - PullRequest
3 голосов
/ 31 марта 2011

Я создавал таблицы, добавляя ListView (предоставляя мои данные в виде List<MyObject>) на страницу, и назначая соответствующие идентификаторы для каждого столбца в HTML-файле.

Однако теперь у меня есть ситуация, когда вместо простого List<MyObject> у меня есть List<Map<String,MyObject>>.Я также получаю список со всеми возможными ключами вложенной карты (List<String>).Теперь мне нужно создать таблицу, в которой каждое значение Map должно быть в столбце, а имя ключа указывает на это значение.

Допустим, у меня есть следующие данные:

keys = ['a', 'b']

data = [ { 'a' = 1, 'b' = 2 },
         { 'a' = 3, 'b' = 4 },
         { 'a' = 5, 'b' = 6}] 

Я хотел бы создать таблицу:

<table>
    <tr>
        <th>a</th>
        <th>b</th>
    </tr>
    <tr>
        <td>1</td>
        <td>2</td>
    </tr>
    <tr>
        <td>3</td>
        <td>4</td>
    </tr>
    <tr>
        <td>5</td>
        <td>6</td>
    </tr>
</table>

Зная, что имена и количество ключей во вложенной карте могут измениться, как лучше всего реализовать это в калитке?

Ответы [ 4 ]

9 голосов
/ 02 апреля 2011

Ниже приведены примеры использования DefaultDataTable и вложенных списков просмотра.

Обратите внимание, что, хотя подход DataTable может выглядеть менее простым (ну, это зависит от взгляда наблюдателя), он фактически отделяет более аккуратную выборку данных от визуализации, и вы получаете пагинацию из коробки: добавление дополнительных данных или понижение rowsPerPage (последний параметр конструктора DefaultDataTable).

public class HomePage extends WebPage {

    static final String A = "a";
    static final String B = "b";

    public HomePage() {
        final List<String> keys = Arrays.asList(A, B);
        final List<Map<String, Integer>> data = Arrays.asList(
            map(A, 1).put(B, 11).toMap(),
            map(A, 2).put(B, 12).toMap(),
            map(A, 3).put(B, 13).toMap(),
            map(A, 4).put(B, 14).toMap(),
            map(A, 5).put(B, 15).toMap(),
            map(A, 6).put(B, 16).toMap(),
            map(A, 7).put(B, 17).toMap(),
            map(A, 8).put(B, 18).toMap(),
            map(A, 9).put(B, 19).toMap());

        // Using a DefaultDataTable
        ISortableDataProvider dataProvider = new SortableDataProvider() {
            public Iterator iterator(int first, int count) {
                int start = Math.min(0, first);
                int end = Math.min(data.size(), start + count);
                return data.subList(start, end).iterator();
            }
            public int size() {
                return data.size();
            }
            public IModel model(Object object) {
                return new CompoundPropertyModel(object);
            }
        };
        List columns = new ArrayList();
        for (String key : keys)
            columns.add(new PropertyColumn(Model.of(key), key));
        add(new DefaultDataTable("dataTable", columns, dataProvider, 20));

        // Using a nested ListViews
        add(new ListView("headers", keys) {
            @Override
            protected void populateItem(ListItem item) {
                item.add(new Label("header", String.valueOf(item.getModelObject())));
            }
        });
        add(new ListView("listView", data) {
            @Override
            protected void populateItem(ListItem item) {
                final Map rowMap = (Map) item.getModelObject();
                item.add(new ListView("nested", keys) {
                    @Override
                    protected void populateItem(ListItem item) {
                        Object value = rowMap.get(item.getModelObject());
                        item.add(new Label("value", String.valueOf(value)));
                    }
                });
            }
        });
    }

    // to make building the data structure a little more fun :)
    private MapBuilder<String, Integer> map(String key, Integer value) {
        return new MapBuilder<String, Integer>().put(key, value);
    }
    private static class MapBuilder<K, V> {
        Map<K, V> map = new HashMap<K, V>();
        MapBuilder<K, V> put(K key, V value) {
            map.put(key, value);
            return this;
        }
        Map<K, V> toMap() {
            return map;
        }
    }
}


<html xmlns:wicket="http://wicket.apache.org">
<body>

  <table wicket:id="dataTable"></table>

  <table>
    <tr>
      <th wicket:id="headers">
          <span wicket:id="header"></span>
      </th>
    </tr>
    <tr wicket:id="listView">
      <td wicket:id="nested">
        <span wicket:id="value"></span>
      </td>
    </tr>
  </table>

</body>
</html>
7 голосов
/ 31 марта 2011

Вы можете вкладывать ListView.Разметка, которую вы хотите, будет выглядеть примерно так:

<table>
  <tr><th wicket:id="headerlist"><span wicket:id="header"></span></th></tr>
  <tr wicket:id="contentlist"><td wicket:id="column">
    <span wicket:id="data"></span>
  </td></tr>
</table>

Затем вам потребуется три ListView.Первый (headerlist) заполнит заголовки из списка keys.Это просто, поэтому я пропущу пример.

Второй (contentlist) будет в вашем списке data.В методе populateItems вы добавите третий ListView (column), который снова будет перебирать список keys:

add(new ListView<Map<String,MyObject>>("contentlist", data) {
  protected void populateItem(ListItem<Map<String,MyObject>> item) {
    final Map<String,MyObject> map = item.getModelObject();
    // Inner list - using item.add to add to the inner list
    item.add(new ListView<String>("column", keys) {
      protected void populateItem(ListItem<String> item) {
        String key = item.getModelObject();
        item.add(new Label("data", map.get(key).toString()));
      }
    });
  }
});
2 голосов
/ 31 марта 2011

Конечно, вы можете использовать вложенные ListView s, но вы также можете использовать DataTable и его потомков, которые были специально разработаны для этой задачи.В качестве бонуса вы также можете получить такие вещи, как сортировка и разбиение на страницы.

1 голос
/ 10 июля 2015

Спасибо Тецуо! Я заполнил примеры переменных для Generics for Tetsuo:

  1. DefaultDataTable
  2. Вложенные ListViews

Калитка HTML

<html xmlns:wicket="http://wicket.apache.org">
<body>

  <h3>Example 1</h3>
  <table wicket:id="dataTable"></table>

  <br>

  <h3>Example 2</h3>
  <table>

    <tr>
      <th wicket:id="headers">
        <span wicket:id="header"></span>
      </th>
    </tr>

    <tr wicket:id="listView">
      <td wicket:id="nested">
        <span wicket:id="value"></span>
      </td>
    </tr>

  </table>

</body>
</html>

Калитка Ява

public class HomePage extends WebPage 
{
    /** Represents serialVersionUID. */
    private static final long serialVersionUID = 20150701L;

    static final String A = "alpha";
    static final String B = "beta";
    static final String C = "gamma";

    public HomePage()
    {
        super();

        final List<String> keys = Arrays.asList(A, B, C);

        final List<Map<String,Integer>> data = Arrays.asList
        (
            map(A, 1).put(B, 11).put(C, 21).toMap(),
            map(A, 2).put(B, 12).put(C, 22).toMap(),
            map(A, 3).put(B, 13).put(C, 23).toMap(),
            map(A, 4).put(B, 14).put(C, 24).toMap(),
            map(A, 5).put(B, 15).put(C, 25).toMap(),
            map(A, 6).put(B, 16).put(C, 26).toMap(),
            map(A, 7).put(B, 17).put(C, 27).toMap(),
            map(A, 8).put(B, 18).put(C, 28).toMap(),
            map(A, 9).put(B, 19).put(C, 29).toMap()
        );

        // Using a DefaultDataTable
        ISortableDataProvider<Map<String,Integer>,String> dataProvider = 
            new SortableDataProvider<Map<String,Integer>,String>()
        {
            /** Represents serialVersionUID. */
            private static final long serialVersionUID = HomePage.serialVersionUID;

            public Iterator<Map<String,Integer>> iterator(long first, long count)
            {
                int start = Math.max(0, (int) first);
                int end = Math.min(data.size(), start + (int) count);
                return data.subList(start, end).iterator();
            }

            public long size()
            {
                return data.size();
            }

            public IModel<Map<String,Integer>> model(Map<String,Integer> object)
            {
                return new CompoundPropertyModel<Map<String,Integer>>(object);
            }
        };

        List<PropertyColumn<Map<String,Integer>,String>> columns =
            new ArrayList<PropertyColumn<Map<String,Integer>,String>>();

        for (String key : keys)
            columns.add(new PropertyColumn<Map<String,Integer>,String>(Model.of(key), key));

        // Example 1 - Using a DataTable
        // Wicket: "dataTable"
        add(new DefaultDataTable<Map<String,Integer>,String>("dataTable", columns, dataProvider, 5));

        // Example 2 - Using nested ListViews
        // Wicket: "headers"
        add
        (
            new ListView<String>("headers", keys)
            {
                /** Represents serialVersionUID. */
                private static final long serialVersionUID = HomePage.serialVersionUID;

                @Override
                protected void populateItem(ListItem<String> item)
                {
                    // Wicket: "header"
                    item.add(new Label("header", String.valueOf(item.getModelObject())));
                }
            }
        );

        add
        (
            // Wicket: "listView"
            new ListView<Map<String,Integer>>("listView", data)
            {
                /** Represents serialVersionUID. */
                private static final long serialVersionUID = HomePage.serialVersionUID;

                @Override
                protected void populateItem(ListItem<Map<String,Integer>> item)
                {
                    final Map<String,Integer> rowMap = item.getModelObject();
                    item.add
                    (
                        // Wicket: "nested"
                        new ListView<String>("nested", keys)
                        {
                            private static final long serialVersionUID = HomePage.serialVersionUID;
                            @Override
                            protected void populateItem(ListItem<String> item)
                            {
                                Integer value = rowMap.get(item.getModelObject());

                                // Wicket: "value"
                                item.add(new Label("value", String.valueOf(value)));
                            }
                        }
                    );
                }
            }
        );
    }

    // Make building the data structure a little more fun :)
    private MapBuilder<String, Integer> map(String key, Integer value)
    {
        return new MapBuilder<String, Integer>().put(key, value);
    }

    private static class MapBuilder<K, V>
    {
        Map<K, V> map = new HashMap<K, V>();

        MapBuilder<K, V> put(K key, V value)
        {
            map.put(key, value);
            return this;
        }

        Map<K, V> toMap()
        {
            return map;
        }
    }
}

Общее использование

DefaultDataTable расширяет DataTable

  • @ param Тип объекта модели
  • @ param Тип параметра сортировки

IColumn

  • @ param Тип объекта, который будет отображаться в ячейках этого столбца
  • @ param Тип параметра сортировки

ISortableDataProvider

  • @ param Тип объекта модели (отсутствует в JavaDoc) ??
  • @ param Тип параметра сортировки
...