2026-05-18 15:53:07 +05:00
2026-05-18 15:55:02 +05:00

Документация библиотеки CRUD Dialogs

Библиотека для создания модальных диалоговых окон на основе Bootstrap с поддержкой CRUD операций, вкладок и гибкой настройкой макета.

Оглавление

  1. Подключение
  2. Основные концепции
  3. API Reference
  4. Типы полей
  5. Настройки диалога
  6. Layout и категории
  7. Примеры использования

Подключение

<!-- Зависимости -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>

<!-- Библиотека dom.js (должна быть подключена первой) -->
<script src="dom.js"></script>

<!-- Библиотека CRUD Dialogs -->
<script src="crud_d.js"></script>

Основные концепции

Библиотека работает с двумя основными режимами открытия диалога:

  • create — создание нового элемента (пустая форма)
  • update — редактирование существующего элемента (форма с подгруженными данными)

Каждый диалог имеет:

  • Уникальный строковый идентификатор (dialogId)
  • Набор полей с типами и настройками
  • Эндпоинты для CRUD операций (устанавливаются отдельно)
  • Опциональные настройки отображения (ширина, категории)

Управлять диалогом можно:

  • Через объект, полученный при создании
  • Через глобальные методы, используя dialogId

API Reference

makeDialog

Создает новый диалог и возвращает объект для работы с ним.

crud_d.makeDialog(dialogId, fields, options)

Параметры:

Параметр Тип Обязательный Описание
dialogId string Да Уникальный идентификатор диалога (не DOM id)
fields object Да Объект с описанием полей
options object Нет Дополнительные настройки диалога

Возвращает: Объект диалога с методами управления.

Пример:

const dialog = crud_d.makeDialog('user_form', {
    name: ['text', { label: 'Имя', required: true }, ''],
    email: ['email', { label: 'Email', required: true }, '']
}, {
    width: 'lg'
});

Методы объекта диалога

setCreateEndpoint(endpoint)

Устанавливает endpoint для создания элемента (POST).

dialog.setCreateEndpoint('/api/users')

setUpdateEndpoint(endpoint)

Устанавливает endpoint для обновления элемента (PUT). Используйте {id} для подстановки ID элемента.

dialog.setUpdateEndpoint('/api/users/{id}')

setGetEndpoint(endpoint)

Устанавливает endpoint для получения данных элемента (GET). Используйте {id} для подстановки ID элемента.

dialog.setGetEndpoint('/api/users/{id}')

setDeleteEndpoint(endpoint)

Устанавливает endpoint для удаления элемента (DELETE). Используйте {id} для подстановки ID элемента.

dialog.setDeleteEndpoint('/api/users/{id}')

openCreate(title)

Открывает диалог в режиме создания.

dialog.openCreate('Новый пользователь')
    .onSuccess(function(result) {
        console.log('Создан:', result);
    })
    .onError(function(error) {
        console.error('Ошибка:', error);
    });

openUpdate(itemId, title)

Открывает диалог в режиме редактирования. Автоматически загружает данные через GET endpoint.

dialog.openUpdate(42, 'Редактирование пользователя')
    .onSuccess(function(result) {
        console.log('Обновлен:', result);
    })
    .onDelete(function(id) {
        console.log('Удален:', id);
    })
    .onError(function(error) {
        console.error('Ошибка:', error);
    });

getConfig()

Возвращает текущую конфигурацию диалога.

const config = dialog.getConfig();
console.log(config.fields, config.options, config.endpoints);

destroy()

Удаляет регистрацию диалога и закрывает его, если открыт.

dialog.destroy();

Методы API при открытом диалоге

При открытии диалога возвращается объект с методами для управления текущим экземпляром:

const api = dialog.openCreate('Заголовок');

onSuccess(callback)

Устанавливает обработчик успешного выполнения операции.

api.onSuccess(function(result) {
    // result - данные, возвращенные сервером
    console.log('Успех:', result);
});

onError(callback)

Устанавливает обработчик ошибок.

api.onError(function(error) {
    console.error('Ошибка:', error.message);
});

onDelete(callback)

Устанавливает обработчик успешного удаления (только для режима update).

api.onDelete(function(itemId) {
    console.log('Удален элемент с ID:', itemId);
});

setValues(values)

Устанавливает значения полей формы.

api.setValues({
    name: 'Иван',
    email: 'ivan@example.com'
});

getFormData()

Возвращает текущие данные формы.

const data = api.getFormData();
console.log(data);

close()

Закрывает диалог программно.

api.close();

show()

Показывает диалог (если был скрыт).

api.show();

Глобальные методы

Работа с диалогами через глобальный объект crud_d по dialogId.

setCreateEndpoint(dialogId, endpoint)

crud_d.setCreateEndpoint('user_form', '/api/users');

setUpdateEndpoint(dialogId, endpoint)

crud_d.setUpdateEndpoint('user_form', '/api/users/{id}');

setGetEndpoint(dialogId, endpoint)

crud_d.setGetEndpoint('user_form', '/api/users/{id}');

setDeleteEndpoint(dialogId, endpoint)

crud_d.setDeleteEndpoint('user_form', '/api/users/{id}');

openCreate(dialogId, title)

crud_d.openCreate('user_form', 'Новый пользователь')
    .onSuccess(function(result) {
        console.log('Создан:', result);
    });

openUpdate(dialogId, itemId, title)

crud_d.openUpdate('user_form', 42, 'Редактирование')
    .onSuccess(function(result) {
        console.log('Обновлен:', result);
    });

closeDialog(dialogId)

crud_d.closeDialog('user_form');

getRegisteredDialogs()

const dialogs = crud_d.getRegisteredDialogs();
console.log(dialogs); // ['user_form', 'product_form']

closeAll()

crud_d.closeAll();

Типы полей

text

Текстовое поле ввода.

fieldName: ['text', {
    label: 'Название поля',        // string - заголовок
    required: true,                 // boolean - обязательно для заполнения
    placeholder: 'Подсказка',       // string - текст-подсказка
    readonly: false,                // boolean - только для чтения
    maxlength: 100                  // number - максимальная длина
}, 'значение по умолчанию']

number

Числовое поле ввода.

fieldName: ['number', {
    label: 'Цена',
    required: true,
    min: 0,                         // number - минимальное значение
    max: 1000000,                   // number - максимальное значение
    step: 0.01                      // number - шаг изменения
}, 0]

email

Поле для email с валидацией формата.

fieldName: ['email', {
    label: 'Email',
    required: true,
    placeholder: 'user@example.com'
}, '']

password

Поле для пароля (скрытый ввод).

fieldName: ['password', {
    label: 'Пароль',
    required: true,
    placeholder: 'Введите пароль'
}, '']

textarea

Многострочное текстовое поле.

fieldName: ['textarea', {
    label: 'Описание',
    required: false,
    rows: 5                         // number - количество строк
}, '']

select

Выпадающий список.

fieldName: ['select', {
    label: 'Категория',
    required: true,
    options: [                      // array - список опций
        { value: 'electronics', label: 'Электроника' },
        { value: 'books', label: 'Книги' },
        { value: 'clothing', label: 'Одежда' }
    ]
}, 'electronics']                  // значение по умолчанию

checkbox

Флажок (чекбокс).

fieldName: ['checkbox', {
    label: 'Активен',
    required: false
}, true]                           // значение по умолчанию

date

Поле выбора даты.

fieldName: ['date', {
    label: 'Дата рождения',
    required: true
}, '2024-01-01']

custom

Кастомное поле на основе HTMLElement.

const customElement = document.createElement('div');
customElement.innerHTML = `
    <label class="form-label">Цвет</label>
    <input type="color" class="form-control">
`;

fieldName: ['custom', customElement, '#ff0000']

Настройки диалога

Объект options передается третьим параметром в makeDialog:

{
    width: 'lg',                    // Ширина диалога: 'sm', 'lg', 'xl' или CSS значение ('800px', '90%')
    categories: {                   // Категории (вкладки)
        'Основное': [
            ['name', 'price'],
            ['description']
        ],
        'Дополнительно': [
            ['sku', 'weight'],
            ['dimensions']
        ]
    }
}

Layout и категории

Без категорий

Если категории не указаны, все поля отображаются последовательно по одному в ряду.

crud_d.makeDialog('simple', {
    name: ['text', { label: 'Имя' }, ''],
    email: ['email', { label: 'Email' }, ''],
    phone: ['text', { label: 'Телефон' }, '']
});

Layout в категориях

Каждая категория содержит массив рядов. Ряд — это массив имен полей, которые будут в одной строке.

categories: {
    'Основная информация': [
        ['first_name', 'last_name'],     // 2 поля в ряд
        ['email', 'phone'],              // 2 поля в ряд
        ['address']                       // 1 поле в ряд
    ],
    'Дополнительно': [
        ['birth_date', 'gender'],        // 2 поля в ряд
        ['notes']                         // 1 поле в ряд
    ]
}

Автоматическая категория "Дополнительно"

  • Если указана только одна категория, все поля, не попавшие в неё, автоматически добавляются во вкладку "Дополнительно"
  • Если категорий несколько, нераспределенные поля также добавляются в "Дополнительно"
  • Если категории не указаны вообще, все поля идут подряд без вкладок

Ширина колонок в ряду

Автоматически рассчитывается на основе количества полей:

  • 1 поле: col-12 (полная ширина)
  • 2 поля: col-md-6 (по половине)
  • 3 поля: col-md-4 (по трети)
  • 4 поля: col-md-3 (по четверти)

Примеры использования

Простой диалог создания

const dialog = crud_d.makeDialog('simple_user', {
    name: ['text', { label: 'Имя', required: true }, ''],
    email: ['email', { label: 'Email', required: true }, '']
});

dialog.setCreateEndpoint('/api/users');

// Открытие
dialog.openCreate('Новый пользователь')
    .onSuccess(function(result) {
        alert('Пользователь создан!');
    });

Диалог с обновлением и удалением

const dialog = crud_d.makeDialog('user_edit', {
    name: ['text', { label: 'Имя', required: true }, ''],
    email: ['email', { label: 'Email', required: true }, ''],
    role: ['select', {
        label: 'Роль',
        options: [
            { value: 'user', label: 'Пользователь' },
            { value: 'admin', label: 'Администратор' }
        ]
    }, 'user']
});

dialog.setGetEndpoint('/api/users/{id}');
dialog.setUpdateEndpoint('/api/users/{id}');
dialog.setDeleteEndpoint('/api/users/{id}');

// Открытие на редактирование
dialog.openUpdate(42, 'Редактирование пользователя')
    .onSuccess(function(result) {
        console.log('Обновлен:', result);
        // Обновить список пользователей
    })
    .onDelete(function(id) {
        console.log('Удален:', id);
        // Удалить из списка
    })
    .onError(function(error) {
        alert('Ошибка: ' + error.message);
    });

Сложный диалог с категориями

const dialog = crud_d.makeDialog('product_form', {
    name: ['text', { label: 'Название', required: true }, ''],
    price: ['number', { label: 'Цена', required: true, min: 0 }, 0],
    quantity: ['number', { label: 'Количество', min: 0 }, 0],
    category: ['select', {
        label: 'Категория',
        options: [
            { value: 'electronics', label: 'Электроника' },
            { value: 'clothing', label: 'Одежда' }
        ]
    }, 'electronics'],
    description: ['textarea', { label: 'Описание', rows: 5 }, ''],
    weight: ['number', { label: 'Вес (кг)', step: 0.1 }, null],
    dimensions: ['text', { label: 'Размеры' }, ''],
    manufacturer: ['text', { label: 'Производитель' }, ''],
    in_stock: ['checkbox', { label: 'В наличии' }, true]
}, {
    width: 'lg',
    categories: {
        'Основное': [
            ['name'],
            ['price', 'quantity', 'in_stock'],
            ['category'],
            ['description']
        ],
        'Характеристики': [
            ['weight', 'dimensions'],
            ['manufacturer']
        ]
    }
});

dialog.setCreateEndpoint('/api/products');
dialog.setGetEndpoint('/api/products/{id}');
dialog.setUpdateEndpoint('/api/products/{id}');
dialog.setDeleteEndpoint('/api/products/{id}');

Глобальное управление

// Регистрируем диалог
crud_d.makeDialog('quick_user', {
    name: ['text', { label: 'Имя' }, ''],
    email: ['email', { label: 'Email' }, '']
});

// Устанавливаем эндпоинты глобально
crud_d.setCreateEndpoint('quick_user', '/api/users');
crud_d.setGetEndpoint('quick_user', '/api/users/{id}');

// Открываем из любого места
crud_d.openCreate('quick_user', 'Быстрое создание')
    .onSuccess(function(result) {
        console.log('Готово!', result);
    });

// Закрываем при необходимости
crud_d.closeDialog('quick_user');

// Закрыть все открытые диалоги
crud_d.closeAll();

Кастомное поле

// Создаем кастомный элемент для выбора цвета
const colorPicker = document.createElement('div');
colorPicker.className = 'mb-3';
colorPicker.innerHTML = `
    <label class="form-label">Цвет товара</label>
    <div class="input-group">
        <input type="color" class="form-control form-control-color" 
               value="#563d7c" title="Выберите цвет">
        <input type="text" class="form-control" value="#563d7c">
    </div>
`;

// Синхронизация инпутов
const [colorInput, textInput] = colorPicker.querySelectorAll('input');
colorInput.addEventListener('input', () => textInput.value = colorInput.value);
textInput.addEventListener('input', () => colorInput.value = textInput.value);

const dialog = crud_d.makeDialog('custom_example', {
    name: ['text', { label: 'Название' }, ''],
    color: ['custom', colorPicker, '#563d7c']
});

dialog.setCreateEndpoint('/api/products');
dialog.openCreate('Товар с цветом');

Установка значений по умолчанию

dialog.openCreate('Новый заказ')
    .setValues({
        priority: 'high',
        status: 'pending',
        date: new Date().toISOString().split('T')[0]
    })
    .onSuccess(function(result) {
        console.log('Заказ создан:', result);
    });

События и колбэки

Порядок выполнения

  1. Создание (create):

    • Валидация формы
    • POST запрос на create endpoint
    • onSuccess при успехе
    • onError при ошибке
    • Автоматическое закрытие диалога при успехе
  2. Обновление (update):

    • GET запрос на get endpoint для загрузки данных
    • Заполнение формы полученными данными
    • При сохранении: валидация → PUT запрос → onSuccess/onError
    • При удалении: подтверждение → DELETE запрос → onDelete/onError
    • Автоматическое закрытие диалога при успехе

Цепочка методов

Все методы настройки возвращают this, что позволяет использовать цепочку вызовов:

dialog
    .setCreateEndpoint('/api/users')
    .setGetEndpoint('/api/users/{id}')
    .openCreate('Пользователь')
    .onSuccess(handleSuccess)
    .onError(handleError);

Обработка ошибок

Библиотека автоматически обрабатывает HTTP ошибки и отображает их в диалоге:

  • Ошибки валидации отображаются в alert-блоке внутри диалога
  • Ошибки сети/сервера отображаются там же
  • Все ошибки также передаются в onError колбэк
dialog.openCreate('Форма')
    .onError(function(error) {
        // error.message содержит текст ошибки
        if (error.message.includes('422')) {
            // Ошибка валидации на сервере
        } else if (error.message.includes('500')) {
            // Ошибка сервера
        }
    });

Примечания

  • Все эндпоинты поддерживают подстановку {id} в URL
  • При закрытии диалога через data-bs-dismiss="modal" он автоматически очищается
  • Одновременно может быть открыт только один экземпляр диалога с одинаковым dialogId
  • Библиотека требует Bootstrap 5 и библиотеку dom.js
  • Все HTTP запросы отправляются с заголовком Content-Type: application/json
Description
Библиотека для абстракции создания диалогов для CRUD операций. Требует bootstrap и dom.js
Readme MIT 78 KiB
2026-05-19 05:35:10 +05:00
Languages
HTML 50.5%
JavaScript 49.5%