days to give it a try before you buy! Download now. The best deals on licenses are coming soon Download now. The best deals on licenses are coming soon

Различные способы редактирования табличных данных

Библиотека Webix предлагает несколько способов редактирования табличных данных. Одни из самых распространённых практик — использование встроенных редакторов Datatable или же отдельных Webix Form. Однако вопрос остаётся открытым — как удачно подобрать инструменты и предоставить пользователю удобное и интуитивно-понятное решение?

ПАРАМЕТРЫ ФАЙЛА  exploring_different techniques for data editing

Используем встроенный редактор

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

Попробуйте внести изменения в таблицу:

View code >>

На первый взгляд, всё работает отлично. Однако этот подход не может похвастаться эффективностью, т.к. при каждом сохранении данных в редакторе, таблица отправляет эти данные на сервер. Чтобы обойти такое поведение, мы можем редактировать весь ряд целиком с помощью метода editRow. В последнюю колонку добавим иконку, при клике по которой будет открываться редактор для всего ряда:

{
  view:"datatable",
  editable: true,
  editaction: "custom",
  columns:[
   // данные столбцов

   // иконка редактирования
   {template: `<span class='webix_icon wxi-dots'></span>`}
  ]
  onClick: {
    "wxi-dots": function(ev, id) {
         this.editRow(id);
     }
  }
}

Теперь можно редактировать сразу весь ряд:

View code >>

Возможно, вы заметили, что после выбора опции из комбо-бокса, все редакторы закрываются. Дело в том, что Webix завершает текущее редактирование, если пользователь выбрал какую-либо опцию комбо. То же самое касается и кликов за пределами редактируемого ряда — редактирование также завершается. Но что, если нам необходимо начинать и завершать редактирование строго при клике по определённому контролу?

Редактирование с Webix Form

Простое и стабильное решение — использовать форму внутри модального окна, как в примере ниже:

View code >>

Редактирование работает так, как нужно да и выглядит неплохо. Однако давайте пойдём ещё дальше и добавим форму прямо в редактируемый ряд.

Встроенный редактор с формой

Форма будет находиться внутри Webix Window и мы можем стилизовать её так, что она не будет отличатся от встроенного редактора Datatable.

Выглядит это следующим образом:

View code >>

То, что нужно!

На что обратить внимание

Далее мы рассмотрим детали и неочевидные моменты нашего решения.

Таблица

В последнем столбце задайте темплейт для иконки, которая будет показывать текущий статус редактирования: “wxi-dots” если редактирование не активно и “wxi-check” — если редактор открыт.

{
  view:"datatable",
  id:"grid",
  columns:[
  //  темплейт для иконки
   {width:55, css:"edit", template:function(obj){
     return `<span class='webix_icon wxi-${obj.edit?"check":"dots"}'></span>`;
   }}
  ],  
  // другие свойства
}

Свойство edit у элемента данных показывает текущий статус редактирования и меняется с вызовом соответствующих функций editStart и editEnd, которые описаны ниже.

Окно и форма

При стилизации окна спрячьте в нём всё, что выдаёт в нём окно. Скройте хедер и уберите границы. Само окно необходимо поместить в контейнер таблицы, чтобы обеспечить его корректное позиционирование при скролле.

{
  view:"window",
  id:"editor",
  height: 50,
  container:$$("grid").$view,
  head:false,
  borderless:true,
  // … другие свойства
}

Высота формы должна совпадать с высотой ряда (в нашем случае это 50px). Ширина контролов должна совпадать с шириной столбцов. В зависимости от типа данных добавьте соответствующие контролы для редактирования. Если какие-либо поля не нужно редактировать, используйте Webix labels, как показано в примере ниже:

// внутри окна
body:{
  view:"form",
  padding:0, height:49, margin:0,
  cols:[
     // ярлыки для нередактируемых полей
     {view:"label", css:"mylabel", width:40, name:"rank"},
     {view:"combo", width:100, name:"catId", options:cats},
     {view:"text", width:100, name:"votes"},
     {view:"datepicker", width:120, name:"start", editable:true}
}

Процесс редактирования

Начало редактирования

В нашем случае редактирование начинается при клике по кнопке (иконка “wxi-dots”). Функция-стартер получает значения текущего ряда и записывает их в соответствующие поля формы. В момент редактирования иконка “wxi-dots” заменяется на “wxi-check”.

function editStart(e, id){
 //…
  const vals = grid.getItem(itemId);
  form.setValues(vals);

// редактор открыт
  vals.edit = true;
  grid.refresh(itemId);
}

Важно расположить окно точно поверх ряда. Для этой цели используйте метод окна show. Обратите внимание, что свойства “х” и “y” рассчитываются с учётом смещения таблицы относительно document.body. Такой подход позволит корректно отображать редакторы таблицы вне зависимости от того, в какой лейаут она встроена.

// позиция таблицы
const offset = webix.html.offset($$("grid").$view);
const xOffset = offset.x;
const yOffset = offset.y;
// ...
function showForm(id){
  // позиция ряда
  const node = grid.getItemNode(id);
  if(node){
    const pos = webix.html.offset(node);
    editor.show({x:pos.x-xOffset, y:pos.y-yOffset-1});
  }
// другие свойства
}

Функция showForm также вызывается после каждого скролла, что обеспечивает корректное позиционирование редактора при скролле содержимого таблицы.

{
   view:"datatable",
   on:{
     onAfterScroll:function(){
       if(itemId) showForm(itemId);
     }
   },
      // другие свойства
 }

Конец редактирования

При клике по иконке “wxi-check” форма валидирует свои значения и сохраняет их, если они соответствуют заданным правилам.

function editEnd(){
  if(form.validate()){
    const vals = form.getValues();
    // редактирование завершено
    vals.edit = false;

    if(form.isDirty())
      grid.updateItem(itemId, vals);
    else {
      grid.getItem(itemId).edit = false;
      grid.refresh(itemId);
    }
// ...
  }
}

Вы можете проверить, внёс ли пользователь изменения с помощью метода isDirty. Если изменения внесены — вызываем метод updateItem, который отрисует новые данные в таблице и отправит их на сервер. Если же пользователь не вводил никаких данных, просто меняем иконку обратно на “wxi-dots” с помощью метода refresh.

Решение для горизонтального скролла

Если вам нужна таблица с горизонтальным скроллом, её необходимо обернуть в scrollView, а свойству scroll задать значение “X”. Это обеспечит корректное позиционирование и отрисовку редактора.

{view:"scrollview", id:"scrolls", scroll:"x", body:{
  view:"datatable",
  id:"grid",
  rowHeight:50,
  autowidth:true,
// other properties
}};

Необходимо также учитывать насколько пользователь проскроллил содержимое таблицы. С помощью метода getScrollState можно получить текущую позицию скролла и затем расположить окно, опираясь на это значение. В примере ниже текущая позиция скролла доступна как state.x.

function showForm(id){
  const node = grid.getItemNode(id);

  const pos = webix.html.offset(node);
  const state = scrolls.getScrollState();
  editor.show({
    x:pos.x-xOffset+state.x,
    y:pos.y-yOffset
  });
}

Datatable c горизонтальным скроллом:

View code >>

Что дальше

А как вы решили бы эту задачу? Поделитесь мыслями по поводу нашего решения или предложите своё в комментариях ниже.