Перейти к содержанию

Таблица. Колонки#

Для примера создадим таблицу «Прайс-лист» с перечнем товаров и цен, и по отдельной кнопке вычислим среднюю цену и количество товаров, выведем ее в отдельном поле.

В существующую форму ControlsForm.xml добавим таблицу. Для этого в макете добавьте следующий код: (Добавление в ControlsForm.xml таблицы)

<Group caption='Прайс лист' id='gr3' editorWidth='12' showBorder='true'>
      <Grid caption='Товары' id='Grid1' editorWidth='6' selectionMode='singlecell' height='300px' >
        <Column text='Цена' datafield='Price' width='20%' >
          <NumberInput/>
        </Column>
        <Column text='Товар' datafield='Material' width='80%' >
          <TextBox />
        </Column>
      </Grid>
    </Group>

После сборки на форме должна появиться группа с таблицей:

Протестируйте результат: создайте несколько строк и заполните цену и товар.

Теперь добавим в группу после Grid кнопку и поле для вывода:(Добавление кнопки и текстового поля)

1
2
3
4
5
<Group caption='' id='gr4' editorWidth='3' showBorder='false'>
        <Button value='Calc' id='ButtonCalc' captionWidth='0' editorWidth='1' width='100%' clicked='ButtonCalc_clicked' />
        <Break />
        <TextBox caption='Результат' id='TextBoxTabRes' captionWidth='1' editorWidth='2' width='100%' />
      </Group>

Результат:

В Лексеме элементы управления полноценно работают только с Observable объектами (библиотека Knockout). Поэтому для начала надо проинициализировать его содержимое, чтобы была возможность добавлять и удалять строки. Сделаем это при загрузке формы (из конструктора класса). Добавьте в класс формы:

1
2
3
4
5
constructor(...args){
    super(...args);

    this.controls.Grid1.dataSource = ko.mapping.fromJS([]);
  }

Приведение обычных объектов в Observable выполняется функцией ko.mapping.fromJS(), наоборот функцией: ko.mapping.toJS().

Чтобы получить результат объекта в Observable формате, надо выполнить его как функцию, результат ее выполнения - значение объекта. Что бы присвоить значение - вызвать как функцию и ее в параметр вставить новое значение.

Вводить информацию в таблицу при каждом запуске неудобно, добавим автоматическое заполнение при загрузке. Для этого добавим в класс формы свойство dataGrid: (Свойство dataGrid)

1
2
3
4
5
6
7
get dataGrid() {
    return [
      {Price: 60.88, Material: 'Яблоки', MaterialGroup: 'Фрукты'}, 
      {Price: 80, Material: 'Апельсины', MaterialGroup: 'Фрукты'}, 
      {Price: 170.22, Material: 'Сыр Белебеевский', MaterialGroup: 'Сыры'}
    ]
  }

Теперь вместо пустого массива передадим в таблицу этот массив:

this.controls.Grid1.dataSource = ko.mapping.fromJS(this.dataGrid);

В ControlsForm.js файл добавим реализацию для нажатия на кнопку Calc (ButtonCalc_clicked). (Реализация функции ButtonCalc_clicked)

1
2
3
4
5
6
7
8
9
ButtonCalc_clicked() {
    let sum = 0;
    let cnt = 0;
    this.controls.Grid1.dataSource().forEach(e => {
      sum += e.Price();
      cnt++;
    });
    this.controls.TextBoxTabRes.value = sum / cnt;
  }

Результат:

Содержимое таблицы хранится в свойстве dataSource. Так как это он в Observable форме, то обращаемся к нему вызвав его как функцию. Аналогично с его свойством Price.

В нашем примере цена имеет строго целое значение, но цена может быть дробной, добавим формат выводимого значения. Для этого в макете добавим свойство cellsformat в колонку указав формат.

<Column text='Цена' datafield='Price' width='15%' cellsformat='D2' >

*Формат D означает дробное число, 2 - количество знаков после запятой.

Результат:

Самостоятельно сделайте проверку на сумму, надо не учитывать строки с отсутствующей суммой.

Группировка#

Добавим в таблицу еще один столбец “Группа товара” и сделаем группировку по нему. Чтобы уместить новую колонку в таблицу, уменьшим “Товар” до 40%. (Добавление столбца “Группа товара”)

1
2
3
<Column text='Группа товара' datafield='MaterialGroup' width='40%' >
  <TextBox />
</Column>

Результат:

Теперь настроим возможность группировки в Grid, добавьте к его параметрам:

groupable='true'

Должно появиться поле для группировки:

Проверим как работает: заполните несколько строк и перетащите заголовок столбца “Группа товара” в панель группировки. Результат:

Но при загрузке формы эта группировка не сохранится. Есть возможность указать группировку из кода, настроим ее при загрузке формы. Добавьте в конструктор формы строку:

this.controls.Grid1.addGrouping('MaterialGroup', 0);

Теперь при открытии формы у таблицы будет включена нужная группировка.

Изображение в ячейке#

Добавим иконку в ячейку и сделаем вывод в текстовое поле информацию о товаре. В ControlsForm.xml добавим новую колонку ‘Info’, вдобавок поменяем местами столбцы и настроим ширину. (Добавление столбца “Info”)

1
2
3
<Column text="" datafield="Info" editable = 'false' width='40px' >
          <GlyphTextBox imageRenderer='info_imageRenderer'/>
        </Column>

Вынесем сперва столбец, по которому настроена группировка, в конец вынесем столбец с иконкой (c фиксированной шириной).

В ControlsForm.js добавим реализацию метода info_imageRenderer. (Реализация метода info_imageRenderer)

1
2
3
info_imageRenderer() {
    return infoImg;
  }

Вверх в модуль добавим импорт картинки для infoImg. (Импорт картинки для infoImg)

import infoImg from 'current-theme/images/dark/help.png';

Результат:

Событие#

Клик в ячейку#

Теперь надо отловить событие нажатия на колонку с иконкой и вывести нужную информацию. В параметр Grid добавьте:

cellClicked='Grid1_cellClicked'

В файл ControlsForm.js добавим его реализацию

1
2
3
Grid1_cellClicked({ args }) {
    console.log(args);
  }

Теперь при клике в ячейку в консоли браузера будет выводиться информацию о событии.

Добавим условие, чтобы:

Выводилась информация о текущем товаре.

Вывод работал только при нажатии на ячейку “Инфо”.

Изменим реализацию:

1
2
3
4
5
Grid1_cellClicked({ args }) {
    if (args.datafield == 'Info') {
      this.controls.TextBoxTabRes.value = `${args.row.bounddata.Material} по ${args.row.bounddata.Price} руб`;
    }
  }

Результат при нажатии на Инфо в 1й строке:

Для завершения выведем пояснение при наведении на ячейку “Инфо”. В макете в столбце добавьте параметр:

hint='Вывести информацию по товару'

Результат:

Закраска ячейки#

В ControlsForm.xml добавим в Grid следующий параметр:

cellPainter='Grid1_cellPainter'

В ControlsForm.js добавим реализацию 'Grid1_cellPainter':

1
2
3
Grid1_cellPainter({}, { column, data, row, value }) {
    return null;
  }

Данная функция всегда должна возвращать значение - цвет. Коллекция цветов содержится в объекте Colors Лексемы. Поэтому надо сперва его импортировать, добавим его в строку импорта:

import { Form, Colors } from 'ecosoft-lexema8'; // импорт компонентов из библиотеки ecosoft-lexema8

Добавим условие в функцию возврата цвета, пусть ячейки в колонке Price будут жёлтые, если больше 100, иначе зеленые, и синим закрасить весь столбец Info.

1
2
3
4
5
Grid1_cellPainter({}, { column, data, row, value }) {
    return column == 'Price' ? (value > 100 ? Colors.yellow : Colors.green) 
      : (column == 'Info') ? Colors.indigo 
      : null;
  }

Суммовые поля#

Добавим в таблицу итоговое поле для цены, содержащее среднюю цену. В Grid добавим параметры showAggregates='true' showStatusBar='true'. В ControlsForm.xml в колонку с ценой надо добавить ColumnAggregate :

1
2
3
4
<Column text='Цена' datafield='Price' width='15%' cellsformat='D2' >
          <NumberInput />
          <ColumnAggregate type="avg" />
        </Column>

В type укажем avg, то есть среднее. теперь можно сравнить с нашим значением.

Обычно это поле используется для вывода суммы по колонке, в этом случае type=‘sum’.

Первая строка выводит сумму по строке, вторая сумма по выделенным строкам. В данный момент выделение у таблицы тип выделения стоит singlecell, изменим его на multiplerows, чтобы можно было выделить несколько строк.

Результат:

В данном примере выделены строки 1 и 2.

Группа колонок#

Объединим колонки «Группа товара» и «Товар» в единую группу «Товар», а колонки переименуем в «Группа» и «Наименование». Для этого обернем обе колонки в ColumnGroup.

1
2
3
4
5
6
7
8
<ColumnGroup name="group1" text='Товар'> 
          <Column text='Группа' datafield='MaterialGroup' width='25%' >
            <TextBox />
          </Column>
          <Column text='Наименование' datafield='Material' width='50%' >
            <TextBox />
          </Column>
        </ColumnGroup>

Также можно сделать высоту таблицы хотя бы 400px, и спрятать с формы группы с примерами их предыдущей практики, чтобы не мешались, добавив параметр visible='false'.

Результат: