Для реализации функционала FullCalendar с созданием и редактированием событий через модальное окно, сохранением и редактированием событий через AJAX на PHP, а также хранением данных в JSON-файле, можно следовать следующему плану:
index.html — основной файл с FullCalendar и модальным окном.
style.css — стили для календаря и модального окна.
script.js — JavaScript-код для работы с FullCalendar и AJAX.
save_event.php — PHP-скрипт для сохранения и редактирования событий.
events.json — JSON-файл для хранения событий.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>FullCalendar Example</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fullcalendar@5.10.1/main.min.css"> <link rel="stylesheet" href="style.css"> </head> <body> <div id="calendar"></div> <!-- Modal --> <div id="eventModal" class="modal"> <div class="modal-content"> <span class="close">×</span> <form id="eventForm"> <input type="hidden" id="eventId"> <label for="eventTitle">Title:</label> <input type="text" id="eventTitle" required> <label for="eventColor">Color:</label> <select id="eventColor" required> <option value="#ff0000">Red</option> <option value="#00ff00">Green</option> <option value="#0000ff">Blue</option> <option value="#ffff00">Yellow</option> <option value="#ff00ff">Magenta</option> <option value="#00ffff">Cyan</option> <option value="#ffa500">Orange</option> </select> <label for="eventStart">Start:</label> <input type="datetime-local" id="eventStart" required> <label for="eventEnd">End:</label> <input type="datetime-local" id="eventEnd"> <button type="submit">Save</button> </form> </div> </div> <script src="https://cdn.jsdelivr.net/npm/fullcalendar@5.10.1/main.min.js"></script> <script src="script.js"></script> </body> </html>
body { font-family: Arial, sans-serif; } #calendar { max-width: 900px; margin: 40px auto; } .modal { display: none; position: fixed; z-index: 1; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(0, 0, 0, 0.5); } .modal-content { background-color: #fff; margin: 15% auto; padding: 20px; border: 1px solid #888; width: 80%; max-width: 500px; } .close { color: #aaa; float: right; font-size: 28px; font-weight: bold; } .close:hover, .close:focus { color: black; text-decoration: none; cursor: pointer; }
document.addEventListener('DOMContentLoaded', function() { var calendarEl = document.getElementById('calendar'); var modal = document.getElementById('eventModal'); var closeBtn = document.querySelector('.close'); var eventForm = document.getElementById('eventForm'); var calendar = new FullCalendar.Calendar(calendarEl, { initialView: 'dayGridMonth', events: 'events.json', dateClick: function(info) { openModal({ start: info.dateStr }); }, eventClick: function(info) { openModal(info.event); } }); calendar.render(); function openModal(event) { document.getElementById('eventId').value = event.id || ''; document.getElementById('eventTitle').value = event.title || ''; document.getElementById('eventColor').value = event.backgroundColor || '#ff0000'; document.getElementById('eventStart').value = event.start ? event.start.toISOString().slice(0, 16) : ''; document.getElementById('eventEnd').value = event.end ? event.end.toISOString().slice(0, 16) : ''; modal.style.display = 'block'; } closeBtn.onclick = function() { modal.style.display = 'none'; } window.onclick = function(event) { if (event.target == modal) { modal.style.display = 'none'; } } eventForm.onsubmit = function(e) { e.preventDefault(); var eventData = { id: document.getElementById('eventId').value, title: document.getElementById('eventTitle').value, backgroundColor: document.getElementById('eventColor').value, start: document.getElementById('eventStart').value, end: document.getElementById('eventEnd').value }; saveEvent(eventData); } function saveEvent(eventData) { var xhr = new XMLHttpRequest(); xhr.open('POST', 'save_event.php', true); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.onload = function() { if (xhr.status === 200) { calendar.refetchEvents(); modal.style.display = 'none'; } }; xhr.send(JSON.stringify(eventData)); } });
<?php
$data = json_decode(file_get_contents('php://input'), true);
$events = json_decode(file_get_contents('events.json'), true);
if (empty($data['id'])) {
// Новое событие
$data['id'] = uniqid();
$events[] = $data;
} else {
// Редактирование события
foreach ($events as &$event) {
if ($event['id'] == $data['id']) {
$event = $data;
break;
}
}
}
file_put_contents('events.json', json_encode($events));
echo json_encode(['status' => 'success']);
?>[]
Убедитесь, что у вас установлен локальный сервер (например, XAMPP или OpenServer).
Поместите файлы в папку сервера.
Откройте index.html в браузере.
Убедитесь, что файл events.json доступен для записи веб-сервером.
Для более сложных проектов рекомендуется использовать базу данных (например, MySQL) вместо JSON-файла.
В реальных проектах важно добавить валидацию данных на стороне сервера и клиента.
Этот пример демонстрирует базовую реализацию функционала. В реальных проектах могут потребоваться дополнительные улучшения, такие как обработка ошибок, безопасность (например, защита от XSS и SQL-инъекций), и более сложная логика работы с событиями.
Конечно! Давайте подробнее разберем код в script.js, чтобы было понятно, как работает каждый его компонент.
script.js// Ожидаем, пока весь DOM загрузится document.addEventListener('DOMContentLoaded', function() { // Получаем элемент календаря var calendarEl = document.getElementById('calendar'); // Получаем модальное окно и его элементы var modal = document.getElementById('eventModal'); var closeBtn = document.querySelector('.close'); var eventForm = document.getElementById('eventForm'); // Инициализируем FullCalendar var calendar = new FullCalendar.Calendar(calendarEl, { // Начальный вид календаря (месяц) initialView: 'dayGridMonth', // Загрузка событий из JSON-файла events: 'events.json', // Обработчик клика по дате dateClick: function(info) { // Открываем модальное окно для создания нового события openModal({ start: info.dateStr }); }, // Обработчик клика по событию eventClick: function(info) { // Открываем модальное окно для редактирования существующего события openModal(info.event); } }); // Рендерим календарь calendar.render(); // Функция для открытия модального окна function openModal(event) { // Заполняем форму данными события document.getElementById('eventId').value = event.id || ''; // ID события (если есть) document.getElementById('eventTitle').value = event.title || ''; // Заголовок события document.getElementById('eventColor').value = event.backgroundColor || '#ff0000'; // Цвет события document.getElementById('eventStart').value = event.start ? event.start.toISOString().slice(0, 16) : ''; // Начало события document.getElementById('eventEnd').value = event.end ? event.end.toISOString().slice(0, 16) : ''; // Конец события // Показываем модальное окно modal.style.display = 'block'; } // Закрытие модального окна при клике на крестик closeBtn.onclick = function() { modal.style.display = 'none'; } // Закрытие модального окна при клике вне его области window.onclick = function(event) { if (event.target == modal) { modal.style.display = 'none'; } } // Обработчик отправки формы eventForm.onsubmit = function(e) { e.preventDefault(); // Предотвращаем стандартное поведение формы // Собираем данные из формы var eventData = { id: document.getElementById('eventId').value, // ID события title: document.getElementById('eventTitle').value, // Заголовок backgroundColor: document.getElementById('eventColor').value, // Цвет start: document.getElementById('eventStart').value, // Начало end: document.getElementById('eventEnd').value // Конец }; // Сохраняем событие saveEvent(eventData); } // Функция для сохранения события через AJAX function saveEvent(eventData) { // Создаем новый XMLHttpRequest var xhr = new XMLHttpRequest(); // Настраиваем запрос xhr.open('POST', 'save_event.php', true); xhr.setRequestHeader('Content-Type', 'application/json'); // Обработчик успешного ответа xhr.onload = function() { if (xhr.status === 200) { // Обновляем события в календаре calendar.refetchEvents(); // Закрываем модальное окно modal.style.display = 'none'; } }; // Отправляем данные на сервер xhr.send(JSON.stringify(eventData)); } });
var calendar = new FullCalendar.Calendar(calendarEl, { initialView: 'dayGridMonth', // Начальный вид календаря events: 'events.json', // Загрузка событий из JSON-файла dateClick: function(info) { ... }, // Обработчик клика по дате eventClick: function(info) { ... } // Обработчик клика по событию });
initialView: Указывает, какой вид календаря будет показан по умолчанию (в данном случае — месяц).
events: Указывает источник данных для событий (в данном случае — файл events.json).
dateClick: Срабатывает при клике на дату. Открывает модальное окно для создания нового события.
eventClick: Срабатывает при клике на существующее событие. Открывает модальное окно для его редактирования.
openModalfunction openModal(event) { document.getElementById('eventId').value = event.id || ''; document.getElementById('eventTitle').value = event.title || ''; document.getElementById('eventColor').value = event.backgroundColor || '#ff0000'; document.getElementById('eventStart').value = event.start ? event.start.toISOString().slice(0, 16) : ''; document.getElementById('eventEnd').value = event.end ? event.end.toISOString().slice(0, 16) : ''; modal.style.display = 'block'; }
Заполняет форму данными события:
event.id: ID события (если оно редактируется).
event.title: Заголовок события.
event.backgroundColor: Цвет события.
event.start и event.end: Время начала и окончания события.
Показывает модальное окно.
closeBtn.onclick = function() { modal.style.display = 'none'; } window.onclick = function(event) { if (event.target == modal) { modal.style.display = 'none'; } }
Закрывает модальное окно при клике на крестик или вне его области.
eventForm.onsubmit = function(e) { e.preventDefault(); var eventData = { id: document.getElementById('eventId').value, title: document.getElementById('eventTitle').value, backgroundColor: document.getElementById('eventColor').value, start: document.getElementById('eventStart').value, end: document.getElementById('eventEnd').value }; saveEvent(eventData); }
Собирает данные из формы и передает их в функцию saveEvent.
saveEventfunction saveEvent(eventData) { var xhr = new XMLHttpRequest(); xhr.open('POST', 'save_event.php', true); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.onload = function() { if (xhr.status === 200) { calendar.refetchEvents(); modal.style.display = 'none'; } }; xhr.send(JSON.stringify(eventData)); }
Отправляет данные на сервер через AJAX.
После успешного сохранения обновляет события в календаре и закрывает модальное окно.
Валидация данных:
Проверяйте, что поля title, start и color заполнены.
Убедитесь, что дата окончания (end) не раньше даты начала (start).
Обработка ошибок:
Добавьте обработку ошибок в xhr.onerror для AJAX-запроса.
Выводите сообщения об ошибках пользователю.
Улучшение UX:
Добавьте индикатор загрузки при сохранении события.
Закрывайте модальное окно только после успешного сохранения.
Безопасность:
На стороне сервера (save_event.php) проверяйте и санируйте входящие данные.
Этот код является базовым примером. В реальных проектах его можно расширять и улучшать в зависимости от требований.
Ошибка TypeError: event.start.toISOString is not a function возникает, потому что event.start не является объектом Date, а скорее всего, это строка. В FullCalendar события могут возвращаться как объекты с полями start и end, которые могут быть либо строками, либо объектами Date. Если start или end — это строки, то метод toISOString() не будет доступен.
Чтобы исправить эту ошибку, нужно убедиться, что event.start и event.end преобразуются в объекты Date, если они являются строками. Вот как это можно сделать:
script.jsfunction openModal(event) { // Преобразуем start и end в объекты Date, если они являются строками const start = event.start ? new Date(event.start) : null; const end = event.end ? new Date(event.end) : null; // Заполняем форму данными события document.getElementById('eventId').value = event.id || ''; document.getElementById('eventTitle').value = event.title || ''; document.getElementById('eventColor').value = event.backgroundColor || '#ff0000'; document.getElementById('eventStart').value = start ? start.toISOString().slice(0, 16) : ''; document.getElementById('eventEnd').value = end ? end.toISOString().slice(0, 16) : ''; // Показываем модальное окно modal.style.display = 'block'; }
Преобразование строк в объекты Date:
Если event.start или event.end — это строки, они преобразуются в объекты Date с помощью new Date().
Это гарантирует, что метод toISOString() будет доступен.
Форматирование даты:
Метод toISOString() возвращает дату в формате YYYY-MM-DDTHH:mm:ss.sssZ.
С помощью slice(0, 16) мы обрезаем строку до формата YYYY-MM-DDTHH:mm, который подходит для <input type="datetime-local">.
Если событие приходит из FullCalendar, оно может выглядеть так:
{ id: '123', title: 'Meeting', start: '2023-10-15T10:00:00', // Это строка end: '2023-10-15T11:00:00', // Это строка backgroundColor: '#ff0000' }
После преобразования:
const start = new Date('2023-10-15T10:00:00'); // Объект Date const end = new Date('2023-10-15T11:00:00'); // Объект Date
Теперь методы toISOString() будут работать корректно.
Проверка на валидность даты:
Убедитесь, что event.start и event.end являются валидными датами, прежде чем использовать их.
const start = event.start ? new Date(event.start) : null; if (start && isNaN(start.getTime())) { console.error('Invalid start date'); return; }
Обработка случаев, когда end отсутствует:
Если событие не имеет окончания (end), можно установить значение по умолчанию или оставить поле пустым.
const end = event.end ? new Date(event.end) : null; document.getElementById('eventEnd').value = end ? end.toISOString().slice(0, 16) : '';
Поддержка разных форматов дат:
Если даты могут приходить в разных форматах, используйте библиотеку, например, moment.js или date-fns, для их парсинга.
function openModal(event) { // Преобразуем start и end в объекты Date const start = event.start ? new Date(event.start) : null; const end = event.end ? new Date(event.end) : null; // Проверяем, что даты валидны if (start && isNaN(start.getTime())) { console.error('Invalid start date'); return; } if (end && isNaN(end.getTime())) { console.error('Invalid end date'); return; } // Заполняем форму данными события document.getElementById('eventId').value = event.id || ''; document.getElementById('eventTitle').value = event.title || ''; document.getElementById('eventColor').value = event.backgroundColor || '#ff0000'; document.getElementById('eventStart').value = start ? start.toISOString().slice(0, 16) : ''; document.getElementById('eventEnd').value = end ? end.toISOString().slice(0, 16) : ''; // Показываем модальное окно modal.style.display = 'block'; }
Теперь ошибка TypeError: event.start.toISOString is not a function должна исчезнуть, и форма будет корректно заполняться данными события.
Для реализации задачи с использованием PHP, Bootstrap, DataTables и jQuery, мы создадим:
Таблицу DataTables, которая будет заполнена датами с 2025-01-01 по 2025-10-20.
Форму для выбора интервала дат, которая будет фильтровать таблицу по выбранному диапазону.
index.php — основной файл с таблицей и формой.
style.css — дополнительные стили (если нужны).
script.js — JavaScript для работы с DataTables и фильтрацией.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>DataTables Date Range Filter</title> <!-- Подключаем Bootstrap CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <!-- Подключаем DataTables CSS --> <link href="https://cdn.datatables.net/1.13.6/css/dataTables.bootstrap5.min.css" rel="stylesheet"> </head> <body> <div class="container mt-5"> <h1 class="text-center">DataTables Date Range Filter</h1> <!-- Форма для выбора интервала дат --> <form id="dateRangeForm" class="mb-4"> <div class="row"> <div class="col-md-4"> <label for="startDate">Start Date:</label> <input type="date" id="startDate" class="form-control" required> </div> <div class="col-md-4"> <label for="endDate">End Date:</label> <input type="date" id="endDate" class="form-control" required> </div> <div class="col-md-4 d-flex align-items-end"> <button type="submit" class="btn btn-primary">Filter</button> </div> </div> </form> <!-- Таблица --> <table id="datesTable" class="table table-striped table-bordered"> <thead> <tr> <th>ID</th> <th>Date</th> </tr> </thead> <tbody> <?php // Генерация дат с 2025-01-01 по 2025-10-20 $startDate = new DateTime('2025-01-01'); $endDate = new DateTime('2025-10-20'); $interval = new DateInterval('P1D'); // Интервал в 1 день $dateRange = new DatePeriod($startDate, $interval, $endDate->modify('+1 day')); $id = 1; foreach ($dateRange as $date) { echo "<tr> <td>{$id}</td> <td>{$date->format('Y-m-d')}</td> </tr>"; $id++; } ?> </tbody> </table> </div> <!-- Подключаем jQuery --> <script src="https://code.jquery.com/jquery-3.7.0.min.js"></script> <!-- Подключаем DataTables JS --> <script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script> <script src="https://cdn.datatables.net/1.13.6/js/dataTables.bootstrap5.min.js"></script> <!-- Наш скрипт --> <script src="script.js"></script> </body> </html>
$(document).ready(function() { // Инициализация DataTables var table = $('#datesTable').DataTable({ paging: true, searching: true, ordering: true, info: true, autoWidth: false, columnDefs: [ { targets: 0, width: '50px' }, // Ширина колонки ID { targets: 1, width: '150px' } // Ширина колонки Date ] }); // Обработчик отправки формы $('#dateRangeForm').on('submit', function(e) { e.preventDefault(); // Предотвращаем стандартное поведение формы // Получаем выбранные даты var startDate = $('#startDate').val(); var endDate = $('#endDate').val(); // Фильтруем таблицу по диапазону дат table.columns(1).search('').draw(); // Сбрасываем предыдущий поиск table.column(1).search(startDate + '|' + endDate, true, false).draw(); }); });
Генерируем даты с 2025-01-01 по 2025-10-20 с помощью DateTime, DateInterval и DatePeriod.
Выводим даты в таблицу в формате Y-m-d.
Используем Bootstrap для стилизации формы и таблицы.
Подключаем DataTables для добавления функционала сортировки, поиска и пагинации.
Инициализируем DataTables.
Добавляем обработчик для формы, который фильтрует таблицу по выбранному диапазону дат.
Используем метод column().search() для фильтрации данных в колонке с датами.
Пользователь выбирает начальную и конечную даты в форме.
При отправке формы данные передаются в DataTables.
Метод column().search() ищет значения в колонке с датами, которые попадают в указанный диапазон.
Валидация дат:
Убедитесь, что начальная дата меньше или равна конечной.
if (startDate > endDate) { alert('Start date must be less than or equal to end date.'); return; }
Очистка фильтра:
Добавьте кнопку для сброса фильтра.
<button type="button" id="resetFilter" class="btn btn-secondary">Reset</button>
$('#resetFilter').on('click', function() { $('#startDate').val(''); $('#endDate').val(''); table.columns(1).search('').draw(); });
Поддержка времени:
Если нужно учитывать время, измените формат дат и добавьте соответствующие поля в форму.
Таблица заполнена датами с 2025-01-01 по 2025-10-20.
Форма позволяет фильтровать таблицу по выбранному диапазону дат.
Используются Bootstrap для стилей и DataTables для функционала таблицы.
Этот код можно легко адаптировать под другие задачи, например, для работы с реальными данными из базы данных.
Для обновления таблицы #datesTable каждые 15 секунд с использованием AJAX и данных в формате JSON из файла data.json, нужно выполнить следующие шаги:
index.php — основной файл с таблицей и формой.
data.json — файл с данными в формате JSON.
script.js — JavaScript для работы с DataTables и AJAX.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>DataTables Auto Refresh</title> <!-- Подключаем Bootstrap CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <!-- Подключаем DataTables CSS --> <link href="https://cdn.datatables.net/1.13.6/css/dataTables.bootstrap5.min.css" rel="stylesheet"> </head> <body> <div class="container mt-5"> <h1 class="text-center">DataTables Auto Refresh</h1> <!-- Таблица --> <table id="datesTable" class="table table-striped table-bordered"> <thead> <tr> <th>ID</th> <th>Date</th> </tr> </thead> <tbody> <!-- Данные будут загружены через AJAX --> </tbody> </table> </div> <!-- Подключаем jQuery --> <script src="https://code.jquery.com/jquery-3.7.0.min.js"></script> <!-- Подключаем DataTables JS --> <script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script> <script src="https://cdn.datatables.net/1.13.6/js/dataTables.bootstrap5.min.js"></script> <!-- Наш скрипт --> <script src="script.js"></script> </body> </html>
Пример содержимого файла data.json:
[ { "id": 1, "date": "2025-01-01" }, { "id": 2, "date": "2025-01-02" }, { "id": 3, "date": "2025-01-03" }, { "id": 4, "date": "2025-01-04" }, { "id": 5, "date": "2025-01-05" } ]
$(document).ready(function() { // Инициализация DataTables var table = $('#datesTable').DataTable({ paging: true, searching: true, ordering: true, info: true, autoWidth: false, columns: [ { data: 'id', title: 'ID' }, { data: 'date', title: 'Date' } ] }); // Функция для загрузки данных через AJAX function loadData() { $.ajax({ url: 'data.json', // Путь к JSON-файлу method: 'GET', dataType: 'json', success: function(data) { // Очищаем таблицу и добавляем новые данные table.clear().rows.add(data).draw(); }, error: function(xhr, status, error) { console.error('Error loading data:', error); } }); } // Загружаем данные при загрузке страницы loadData(); // Обновляем данные каждые 15 секунд setInterval(loadData, 15000); // 15000 мс = 15 секунд });
Таблица инициализируется с помощью DataTable().
Указываются колонки id и date, которые соответствуют полям в JSON.
Используется метод $.ajax() для загрузки данных из файла data.json.
В случае успеха данные очищаются (table.clear()) и добавляются в таблицу (rows.add(data)).
Таблица перерисовывается с помощью draw().
Функция setInterval() вызывает loadData() каждые 15 секунд (15000 мс).
Добавьте индикатор загрузки, чтобы пользователь знал, что данные обновляются.
function loadData() { $('#loadingIndicator').show(); // Показываем индикатор $.ajax({ url: 'data.json', method: 'GET', dataType: 'json', success: function(data) { table.clear().rows.add(data).draw(); }, error: function(xhr, status, error) { console.error('Error loading data:', error); }, complete: function() { $('#loadingIndicator').hide(); // Скрываем индикатор } }); }
Добавьте индикатор в HTML:
<div id="loadingIndicator" style="display: none;">Loading...</div>
Если файл data.json недоступен, выведите сообщение об ошибке.
error: function(xhr, status, error) { alert('Failed to load data. Please try again later.'); console.error('Error loading data:', error); }
Чтобы избежать частых запросов к серверу, можно использовать кэширование данных на стороне клиента.
Таблица обновляется каждые 15 секунд с использованием AJAX.
Данные загружаются из файла data.json.
Используются DataTables для отображения и управления таблицей.
Этот код можно адаптировать для работы с реальными API или базой данных, заменив data.json на соответствующий источник данных.
Для реализации функционала добавления колонки с кнопкой, открывающей модальное окно для редактирования ряда, и сохранения изменений в файл data.json, выполним следующие шаги:
index.php — основной файл с таблицей, модальным окном и формой.
data.json — файл с данными в формате JSON.
script.js — JavaScript для работы с DataTables, AJAX и модальным окном.
save_data.php — PHP-скрипт для сохранения изменений в data.json.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>DataTables with Edit Modal</title> <!-- Подключаем Bootstrap CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <!-- Подключаем DataTables CSS --> <link href="https://cdn.datatables.net/1.13.6/css/dataTables.bootstrap5.min.css" rel="stylesheet"> </head> <body> <div class="container mt-5"> <h1 class="text-center">DataTables with Edit Modal</h1> <!-- Таблица --> <table id="datesTable" class="table table-striped table-bordered"> <thead> <tr> <th>ID</th> <th>Date</th> <th>Actions</th> <!-- Новая колонка для кнопок --> </tr> </thead> <tbody> <!-- Данные будут загружены через AJAX --> </tbody> </table> </div> <!-- Модальное окно для редактирования --> <div class="modal fade" id="editModal" tabindex="-1" aria-labelledby="editModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="editModalLabel">Edit Row</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <form id="editForm"> <input type="hidden" id="editId"> <div class="mb-3"> <label for="editDate" class="form-label">Date</label> <input type="date" class="form-control" id="editDate" required> </div> <button type="submit" class="btn btn-primary">Save changes</button> </form> </div> </div> </div> </div> <!-- Подключаем jQuery --> <script src="https://code.jquery.com/jquery-3.7.0.min.js"></script> <!-- Подключаем Bootstrap JS --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <!-- Подключаем DataTables JS --> <script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script> <script src="https://cdn.datatables.net/1.13.6/js/dataTables.bootstrap5.min.js"></script> <!-- Наш скрипт --> <script src="script.js"></script> </body> </html>
Пример содержимого файла data.json:
[ { "id": 1, "date": "2025-01-01" }, { "id": 2, "date": "2025-01-02" }, { "id": 3, "date": "2025-01-03" }, { "id": 4, "date": "2025-01-04" }, { "id": 5, "date": "2025-01-05" } ]
$(document).ready(function() { // Инициализация DataTables var table = $('#datesTable').DataTable({ paging: true, searching: true, ordering: true, info: true, autoWidth: false, columns: [ { data: 'id', title: 'ID' }, { data: 'date', title: 'Date' }, { data: null, title: 'Actions', render: function(data, type, row) { return `<button class="btn btn-sm btn-primary edit-btn" data-id="${row.id}">Edit</button>`; } } ] }); // Функция для загрузки данных через AJAX function loadData() { $.ajax({ url: 'data.json', method: 'GET', dataType: 'json', success: function(data) { table.clear().rows.add(data).draw(); }, error: function(xhr, status, error) { console.error('Error loading data:', error); } }); } // Загружаем данные при загрузке страницы loadData(); // Обновляем данные каждые 15 секунд setInterval(loadData, 15000); // Обработчик клика по кнопке "Edit" $('#datesTable').on('click', '.edit-btn', function() { var id = $(this).data('id'); var row = table.row($(this).closest('tr')).data(); // Заполняем модальное окно данными $('#editId').val(row.id); $('#editDate').val(row.date); // Открываем модальное окно $('#editModal').modal('show'); }); // Обработчик отправки формы редактирования $('#editForm').on('submit', function(e) { e.preventDefault(); var id = $('#editId').val(); var date = $('#editDate').val(); // Отправляем данные на сервер $.ajax({ url: 'save_data.php', method: 'POST', dataType: 'json', data: { id: id, date: date }, success: function(response) { if (response.status === 'success') { // Закрываем модальное окно $('#editModal').modal('hide'); // Обновляем данные в таблице loadData(); } else { alert('Failed to save data.'); } }, error: function(xhr, status, error) { console.error('Error saving data:', error); } }); }); });
<?php
// Получаем данные из POST-запроса
$id = $_POST['id'];
$date = $_POST['date'];
// Загружаем данные из файла
$data = json_decode(file_get_contents('data.json'), true);
// Находим и обновляем запись
foreach ($data as &$item) {
if ($item['id'] == $id) {
$item['date'] = $date;
break;
}
}
// Сохраняем обновленные данные в файл
file_put_contents('data.json', json_encode($data));
// Возвращаем ответ
echo json_encode(['status' => 'success']);
?>В DataTables добавлена колонка Actions, которая содержит кнопку "Edit".
Кнопка имеет атрибут data-id, который хранит ID записи.
При клике на кнопку "Edit" открывается модальное окно, заполненное данными выбранной записи.
При отправке формы данные отправляются на сервер через AJAX.
Серверный скрипт save_data.php обновляет данные в файле data.json.
После успешного сохранения данных таблица обновляется через loadData().
Добавлена колонка с кнопкой для редактирования записей.
Реализовано модальное окно для редактирования данных.
Изменения сохраняются в файл data.json и автоматически обновляются в таблице.
Этот код можно расширить, добавив валидацию, обработку ошибок и другие улучшения.