Контекстное меню для ember-models-table

Таблица с контекстным меню

TL;DR Готовая демка по ссылке — Context Menu Integration

Контекстное меню — это очень удобный инструмент для взаимодействия пользователя с элементами приложения.

Ниже мы разберем, как создать контекстное меню для таблицы из ember-models-table. Известно, что многие задачи бывают решены еще до того, как возникнут конкретно у вас. Вот и для Ember уже есть готовый аддон ember-context-menu, в котором есть весь необходимый базовый функционал для создания контекстного меню.

Что же именно мы хотим сделать? Пусть для каждой строки таблицы контекстное меню будет состоять из таких пунктов:

  • Edit
  • Delete

Если же выбран пункт Edit, то вместо него будет два других пункта:

  • Cancel edit
  • Save

Пункт Delete будет в любом случае.

Нам надо изменить Компонент models-table/row. Чтоб не влазить в существующее стандартное оформление, создадим свою тему my-bs4. В демонстрационных целях таблица будет с использованием Twitter Bootstrap 4, который «монтируется» в Ember с помощью аддона ember-bootstrap.

Создаем тему my-bs4 следующей командой:

1
ember g emt-theme my-bs4

В результате будет создано два файла:

  • app/themes/my-bs4.js
  • app/initializers/my-bs4.js

В первый файл надо внести изменения, так как изначально новые темы наследуются от темы default, а нам надо, чтоб наследование было от ember-bootstrap-v4:

1
2
3
4
// app/themes/my-bs4.js
import Bootstrap4Theme from './ember-bootstrap-v4';
 
export default Bootstrap4Theme.extend({});

Новую тему можно сразу внедрить в Компонент models-table создав Инициализатор Экземпляра Приложения:

1
ember g instance-initializer my-bs4-theme

В полученный файл app/instance-initializers/my-bs4-theme.js запишем следующее:

1
2
3
4
5
6
7
8
9
10
// app/instance-initializers/my-bs4-theme.js
export function initialize(appInstance) {
  appInstance.inject('component:models-table', 'themeInstance', 'theme:my-bs4');
}
 
export default {
  name: 'my-bs4-theme',
  after: 'emt-inject',
  initialize
};

Тут с помощью appInstance.inject в свойство themeInstance Фабрики component:models-table внедряется Фабрика theme:my-bs4. Важно указать, что наш созданный Инициализатор Экземпляра Приложения выполнялся после emt-inject из аддона ember-models-table То есть, так мы гарантируем, что именно наша тема my-bs4 будет использоваться.

Нам надо создать свой Компонент для строки таблицы. Выполним следующую команду:

1
ember g component models-table/themes/my-bs4/custom-row

В результате получим файл app/components/models-table/themes/my-bs4/custom-row.ks, в который запишем следующее:

1
2
3
4
import Row from 'ember-models-table/components/models-table/row';
import ContextMenuMixin from 'ember-context-menu';
 
export default Row.extend(ContextMenuMixin, {});

Здесь Row — это стандартный Компонент для строки таблицы из ember-models-table, а ContextMenuMixin — это основная Миксина (Примесь) для создания контекстного меню из аддона ember-context-menu.

Как известно, ember-models-table «из коробки» поддерживает редактирование строк. И для определения состояния редактирования у Row есть флаг isEditRow. На его основе и будем формировать список доступных пунктов в контекстном меню:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import {computed, get} from '@ember/object';
import Row from 'ember-models-table/components/models-table/row';
import ContextMenuMixin from 'ember-context-menu';
 
export default Row.extend(ContextMenuMixin, {
 
  modalsManager: service(),
 
  contextItems: computed('isEditRow', function () {
    const self = this;
    const common = [
      {
      	label: 'Delete',
        action() {
          return get(self, 'record').destroyRecord();
      	}
      }
    ];
    if (get(self, 'isEditRow')) {
      return [
        ...common,
        {
          label: 'Cancel Edit',
          action (selection, details, event) {
            get(self, 'record').rollbackAttributes();
            seld.send('cancelEditRow');
          }
        },
        {
          label: 'Save',
          action (selection, details, event) {
            get(self, 'record').save();
            self.send('saveRow');
          }
        }
      ];
    }
    return [
      ...common,
	    {
        label: 'Edit',
        action (selection, details, event) {
          self.send('editRow');
        }
      }
    ]
  })
 
});

Шаблон для Row мы используем «оригинальный» и в него не надо вносить никаких изменений.

В объявлении contextItems есть один важный момент — надо сохранить ссылку на this (сам Компонент Row), чтоб использовать send внутри функций-обработчиков кликов на элементах контекстного меню.

В примере подразумевается, что в качестве данных в таблице используются Записи из ember-data, у которых есть соответствующие методы destroyRecord, rollbackAttributes и save.

Удаление Записи — это важный (и часто необратимый процесс), потому лучше чтоб пользователь подтвердил такое действие. Можно воспользоваться методом window.confirm, а можно взять аддон ember-bootstrap-modals-manager и отрисовать красивое модальное окно (так и сделаем).

1
ember i ember-bootstrap-modals-manager

Теперь немного дополним обработчик нажатия на пункт Delete:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import {computed, get} from '@ember/object';
import {inject as service} from '@ember/service';
import Row from 'ember-models-table/components/models-table/row';
import ContextMenuMixin from 'ember-context-menu';
 
export default Row.extend(ContextMenuMixin, {
  modalsManager: service(),
 
  contextItems: computed('isEditRow', function () {
    const self = this;
    const modalsManager = get(self, 'modalsManager');
    const common = [
      {
        label: 'Delete',
        action() {
          return modalsManager
            .confirm({title: 'Please Confirm', body: 'Are you sure?'})
            .then(() => get(self, 'record')
              .destroyRecord()
              .then(() => modalsManager.alert({
                title: 'Deleted successfully',
                body: 'Record is deleted!'
              })));
        }
      }
    ];
    // ....
  })
});

Теперь, при выборе пункта Delete, будет выводиться модальное окно, в котором надо подтвердить удаление Записи. Только после этого Запись будет удалена и будет выведено еше одно модальное окно с сообщением об успешном выполнении запроса.

В данном примере мы разобрались как сделать контекстное меню для строк таблицы. Таким же образом его можно сделать и для заголовка таблицы и даже для отдельных ячеек. Все, что требуется, это создать свою тему, создать несколько Компонентов на основе базовых из ember-models-table и указать их в созданной теме.

Рабочее демо как обычно доступно на ember-twiddle — Context Menu Integration.

, , , , ,

Оставить комментарий

Top ↑ | Main page | Back