Я — начинающий front-end разработчик. Сейчас я учусь и стажируюсь в одной минской IT компании. Изучение основ web-ui проходит на примере JS библиотеки Webix и я хочу поделиться своим скромным опытом и сохранить его в виде небольшого учебного пособия по этой интересной UI библиотеке.

ЧЕТВЕРТАЯ ЗАДАЧА


В работе с данными важно иметь возможность выполнить несколько типов операций. В web разработке за это отвечает CRUD — четыре базовые функции. У библиотеки Webix есть все средства для реализации CRUD. Основой для решения новых задач мне послужит материал из предыдущих публикаций: создание интерфейса приложения, модулей проекта и работа с формами. В этой статье будут рассмотрены следующие задачи:

  • редактирование данных таблицы через форму;
  • установка встроенного редактора строк;
  • добавление данных в список и диаграмму;
  • удаление элементов;

В документации можно ознакомиться с использованными в статье виджетами List, Treetable, Table.

Исходники находятся по ссылке.

С получившимся демо приложения можно ознакомиться тут.

Шаг 1. Редактирование данных через форму


В этом шаге я буду работать со вкладкой «Dashboard» в которой отрисованы таблица и форма. Код таблицы находится в файле table.js, код формы в form.js.

В статье “Работа с формами” новые записи добавлялись методом add(), который был дополнен валидацией формы. Теперь форма будет использована и для редактирования записей.

Виджету Table я добавлю событие onAfterSelect.
При срабатывании этого события я получу данные из таблицы и передам их в поля формы.

const table = {
    view:"datatable", 
    id:"film_list",
    scroll:"y",
    select:true,
    url:"data/data.js",
    hover:"myhover",
    columns:[
        { id:"rank", header:"", width:50, css:"rank"},
        { id:"title", header:"Film title", fillspace:true},
        { id:"year",  header:"Released", width:100},
        { id:"votes", header:"Votes", width:100},
        { id:"rating", header:"Rating", width:100}
    ],
    on:{
        onAfterSelect(id){
            let values = $$("film_list").getItem(id);
            $$("film_form").setValues(values)
        }
    }
}

Метод setValues(), в приведенном коде, отвечает за передачу полученных значений в форму.

Запускаю код и проверяю результат:



Как только строка в таблице выбрана, её данные автоматически попадают в форму и готовы к работе.

Теперь я усложняю процесс: новая запись, как и прежде, будет добавляться в таблицу; если же данные взяты из таблицы и отредактированы, то сохраняю эти изменения.

Перепишу функцию saveItem и добавлю в нее новые методы:

let saveItem = () => {
    let form = $$( "film_form" );  
    let list = $$( "film_list" );  
    let item_data = $$("film_form").getValues();    
    if( form.isDirty() && form.validate() ){
        if( item_data.id ) 
            list.updateItem(item_data.id, item_data);
        else 
            list.add( item_data );
    }
}

Теперь у функции следующий алгоритм:
  • в начале запускается проверка двух условий — прошли ли данные формы валидацию, и произошли ли в форме изменения. Изменения в форме отслеживает метод isDirty();
  • после этого, условие «item_data.id» позволяет определить новую запись. В форму передается строка со всеми ее данными, включая id, для которого в форме нет текстового поля, зато для данных он обязателен. Форма хранит и позволяет считывать все переданные значения, поэтому используем id для проверки;
  • после сверки записей происходит либо добавление новой записи — методом add(), либо обновление текущего элемента новыми свойствами.


Для обновления отредактированных данных используется метод updateItem(). Метод принимает два параметра: id выбранного элемента и набор новых свойств взятых из формы. При вызове функции текущие данные заменяются и дополняются новыми.

Результат:



Шаг 2. Установка встроенного редактора


В предыдущем шаге я рассмотрел вариант редактирования данных таблицы при помощи формы. Но форма на странице нужна не всегда, поэтому я реализую способ редактирования прямо в элементе. Этот способ применим как в таблице, так и в других компонентах для работы с большим количеством данных — например в списке.

Начну с древовидной таблицы во вкладке “Products”. Код таблицы находится в файле products_module.js.

Виджет Treetable позволяет редактировать содержимое таблиц, но по умолчанию эта функция отключена. Редактирование настраивается в двух местах: в конфигурации таблицы, настройкой editable:true, и в конфигурации каждой колонки. Колонкам устанавливается настройка editor:”text”. Атрибут “text” задает тип редактора. Подробнее о типах редактора описано в документации.

const products = {
    editable:true,
    view:"treetable",
    scrollX:false,
    columns:[
        { id:"id", header:"", width:50 },
        { id:"title", header:"Title", fillspace:true, 
        template:"{common.treetable()} #title#", editor:"text" },
        { id:"price", header:"Price", width:200, editor:"text" }
    ],
    select:"row",
    url:"data/products.js",
    rules:{
        "price":webix.rules.isNotEmpty,
        "title":webix.rules.isNotEmpty
    }
}

В коде я добавил редакторы для колонок Title и Price. По клику на любую ячейку в них откроется редактор — текстовое поле:



Теперь перейду во вкладку “Users”, и разберу вариант с редактированием виджета List. Код виджета находится в файле users_module.js.

Редактирование данных доступно по умолчанию для виджетов TreeTable и DataTable.Чтобы использовать встроенный редактор в других виджетах, можно задействовать специальный модуль EditAbility. Этот модуль я использую, чтобы редактировать данные виджета List. Для этого, я на основе виджета LIst я создам пользовательский компонент при помощи метода protoUI.

Записываю имя — свойство name — будущего виджета и наследую для виджет-основы нужные модули.

Прототип виджета List:

webix.protoUI({
    name:"editlist"
}, webix.EditAbility, webix.ui.list);

После вызова protoUI получаю готовый компонент. В виджет он встраивается так же, как и все остальные — настройкой view:"editlist".

view: "editlist",
editable:true,
editor:"text",
editValue:"name",
id:"user_list",
select:true,
url:"data/users.js",
template:"#name# from #country# <span class='webix_icon wxi-close'></span> "
}

Поскольку в каждой записи может быть много полей, а в template листа отрисовано сразу name и country, в конфигурации добавлена настройка — editorValue:”name”, указывающее на то, какое поле можно отредактировать.

Результат:



Шаг 3. Добавление данных в список и диаграмму


В этой части статьи использованы виджеты List и Chart., код которых расположен в файле users_module.js, и отрисован во вкладке "Users".

Виджеты Chart и List используют одни и те же данные — массив JSON. Поэтому когда я реализую возможность добавления данных, нужно чтобы они попадали в оба компонента.

Для этого в модуле users я отрисую кнопку «Add new person».

{
    cols:[
        { 
        view:"button", 
        id:"btn_add_person", 
        value:"Add new person", 
        width:150, css:"webix_primary", 
        click:addPerson
        },
       {}
    ]
}

Клик по кнопке, вызывает функцию addPerson добавляющую в список новую запись.

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

Функция добавления новой записи:

let addPerson = () => {
    let obj = {
        name:"Some name",
        age:Math.floor(Math.random() * 80) + 10, 
        country:"Some country"
    }
    $$("user_list").add(obj);
    $$("chart").add(obj);
};

Результат:



Шаг 4. Удаление элементов


Удаление элементов будет продемонстрировано на примере виджета List — вкладка Users и виджета Table — вкладка "Dashboard".

Для начала, в виджете Table я создам новую колонку в которую помещу html-тег с иконкой.

Чтобы отследить клики по иконкам, нужно использовать свойство таблицы onClick. Это объект, который хранит обработчики, связанные с элементами по одному из их CSS классов — у меня, это "delete_icon".

Для обработки кликов по иконкам, беру их класс delete_icon и записываю его в объект onClick как ключ, значение этого ключа будет функция — наш обработчик. Среди аргументов приходит id записи, так что ничто не мешает её удалить методом remove().

Код виджета Table:

const table = {
    view:"datatable", 
    id:"film_list",
    scroll:"y",
    select:true,
    url:"data/data.js",
    hover:"myhover",
    columns:[
        { id:"rank", header:"", width:50, css:"rank"},
        { id:"title", header:"Film title", fillspace:true},
        { id:"year",  header:"Released", width:100},
        { id:"votes", header:"Votes", width:100},
        { id:"rating", header:"Rating", width:100},
        { header:"", template:"<span class='webix_icon wxi-close delete_icon'></span>", 
        width:35}
    ],
    onClick:{
        delete_icon(e, id){
        this.remove(id);
        return false;
        }
    },
    on:{
        onAfterSelect(id){
            let values = $$("film_list").getItem(id);
            $$("film_form").setValues(values)
        }
    }
}

Алгоритм удаления строки у виджета List, такой же как и у виджета Table:

{
    view: "editlist",
    editable:true,
    editor:"text",
    editValue:"name",
    id:"user_list",
    select:true,
    url:"data/users.js",
    template:`#name# from #country# 
    <span class='webix_icon wxi-close delete_icon'></span> `,
    onClick:{
        delete_icon(e, id){
            this.remove(id);
            return false;
        }
    }
},

Результат удаления строк во вкладке Users:



С готовым приложением можно ознакомиться тут.

Заключение


Реализация CRUD при помощи js библиотеки Webix достигается различными способами: Для изменения данных есть встроенные редакторы, и API, которое позволяет делать то же самое, но уже через стороннюю форму. Добавление данные имеет различные сценарии, а в форме можно осуществить весь набор функций CRUD. Методы реализуются при помощи нескольких строк кода. Архитектура библиотеки позволяет легко комбинировать между собой различные функции.