jQuery + плагины: сортировка и редактирование списка (часть вторая)

Владимир | | Ajax, HTML, JavaScript, PHP, Web разработка.

jquery sortable

В прошлой статье я начал рассказывать о создании редактируемого html списка с возможностью сортировки записей. Мы рассмотрели структуру БД, создали страницу со списком, подключили JS скрипты и разобрали добавление записей.

Осталось немного доделать 😉

Демо-версия находится здесь

Demo

Также вы можете скачать архив с этим примером

Source

Удаление существующих записей

Рассмотрим серверную часть removenote.php.

try {
	if (!isset($_POST['id'])) {
		throw new Exception('Не указан id записи');
	}
	//подключаемся к базе
	require_once('db.php');
	//удаляем запись (id записи приходит в формате note_id, приставку note_ вырезаем)
	$dbh->exec('DELETE FROM notes WHERE id='.$dbh->quote(substr($_POST['id'], 5)));
	$result = array(); 
	$result['id'] = $_POST['id'];
	//отправляет отчет браузеру
	echo json_encode($result);
} catch(Exception $e) {
	echo json_encode(array('err'=>'Ошибка: '.$e->getMessage()));
}

Для удаления записи нам нужно знать только её id. После того, как он получен, выполняем запрос на удаление.

Клиентская часть немного сложнее.

Ссылкам «Удалить» назначается обработчик события click.

.click(removeLi)

function removeLi() {
	//определяем id текущей записи
	var noteId = $(this).parent().attr('id');
	//запрашиваем подтверждение
	if (confirm('Точно удалить?')) {
		//отправляем запрос
		$.post('removenote.php', {'id':noteId}, function(data) {
			var response = eval('('+data+')');
			if (response['err'] != null) {
				alert(response['err']);
			} else {
				$('#' + response['id']).detach();
				//проверяем, остались ли записи в списке
				var notes = $('#sortable li');
				if (notes.length == 0) {
					//удаляем сам список и форму сортировки записей
					$('#sortable').detach();
					$('#changeOrder').detach();
					//добавляем сообщение "Записи отсутствуют"
					$('<h2>Записи отстутствуют</h2>').insertAfter('#addNewNote');
				}
			}
		});
	}
	return false;
}

Этот обработчик определяет id тега li, в котором расположена ссылка, запрашивает подтверждение удаления и отправляет ajax запрос серверу.

После получения ответа от сервера, он удаляет запись из списка с помощью метода .detach() и проверяет, остались ли в списке другие записи. Если не осталось – список вместе с формой сортировки записей также удаляется.

Изменение текста записей

Как и раньше, начинаем с серверной части. Скрипт update.php.

try {
	//проверяем, пришли данные или нет
	if (!isset($_POST['value'])
			|| '' == $_POST['value']
			|| !isset($_POST['id'])
			|| '' == $_POST['id']) {
		throw new Exception('Не указаны данные записи');
	}
	//подключаемся к базе
	require_once('db.php');
	//защита от XSS
	$note = htmlspecialchars($_POST['value']);
	//формируем запрос на изменение записи...
	$stmt = $dbh->prepare('UPDATE notes SET note=:note WHERE id=:id');
	//... и выполняем его
	$stmt->execute(array(':note'=>$note, ':id'=>substr($_POST['id'], 2)));
	$dbh = null;
	//тут мы не используем JSON формат, т.к. это требование плагина jeditable
	echo $note;
} catch(Exception $e) {
	echo 'Ошибка: '.$e->getMessage();
}

От браузера скрипт получает id записи и новый текст.

После выполнения обычных проверок, мы подключаемся к БД и отправляем запрос на изменение записи. При этом с помощью функции htmlspecialchars мы заменяем теги на их эскейп последовательности (защита от XSS). Защита от SQL Injection выполняется с помощью стандартных средств PDO.

Обратите внимание, что в этом случае мы отправляем ответ браузеру в виде обычного текста. Это требование плагина jeditable.

Клиентская часть.

Чтобы сделать текст записей редактируемым, мы для каждого тега span (который находится внутри li) выполняем метод editable.

var editableOptions = {
	indicator : 'Сохраняю...',
	tooltip : 'Сделайте двойной клик, чтобы изменить текст',
	event : 'dblclick',
	cancel : 'Отмена',
	submit : 'Сохранить'
};

$('span.note').editable('update.php', editableOptions);

В параметрах этого метода передаём адрес скрипта, который выполняет обновление записи на сервере, и объект editableOptions, который содержит настройки плагина. В данном случае мы указываем (параметр event), что плагин должен вставить форму редактирования при двойном клике по тексту. Одинарный клик, который используется по-умолчанию, нам не подходит, т.к. в этом случае форма будет появляться при каждой попытке перемещения записи.

Кроме события (dblclick) которое открывает форму редактирования, указанного в параметре event, для настройки плагина мы указали только надписи на кнопках и текст подсказок.

Запрос серверу плагин отправляет сам, после клика по кнопке «Сохранить».

Изменение порядка записей

Самая интересная часть 🙂

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

{
	'id':'id записи',
	'order': порядковый_номер_записи_в_отсортированном_списке
}

Затем этот массив преобразовывается в форма JSON и отправляется серверу.

Примечание. Для преобразования в формат JSON используется плагин jquery-json.

Выглядит клиентская часть следующим образом.

function updateOrder() {
	var notes = $('ul#sortable li');
	//проверяем количество записей в списке
	if (notes.length > 0) {
		var order = [];
		//формируем массив
		//просматриваем список в обратном порядке, т.к. записи выводятся в порядке
		//убывания значений в поле note_order (это позволяет при создании записи
		//присваивать ей максимальный порядковый номер и размещать в начале списка).
		$.each(notes.get().reverse(), function(index, value) {
			order.push({'id': $(value).attr('id'), 'order': index});
		});
		//отправка запроса (метод toJSON добавлен плагином json-2.2)
		$.post('changeorder.php', {'neworder':$.toJSON(order)}, function(data) {
			var response = eval('('+data+')');
			if (response.status == 'OK') {
				$('ul#sortable').effect("highlight", {}, 3000);
			}
			else {
				alert(response.mes);
			}
		});
	}
	return false;
}

Обратите внимание, мы обрабатываем массив с элементами списка в обратном порядке (используется метод .reverse()). Это сделано потому, что записи выводятся в порядке убывания значений в поле note_order. Как я объяснял ранее, такой подход позволяет упростить определение номеров сортировки при создании новых записей.

Если данные успешно сохранены, подсвечиваем список, в противном случае – выводим сообщение об ошибке.

Серверный скрипт (changeorder.php).

try {
	//проверяем полученные данные
	if (!isset($_POST['neworder']) || count($_POST['neworder']) > 5000) {
		throw new Exception('Недопустимые данные');
	}
	//подключаемся к БД
	require_once('db.php');
	//создаём запрос на обновление
	$stmt = $dbh->prepare('UPDATE notes SET note_order=:note_order WHERE id=:id');
	//преобразовываем строку в JSON формате в массив объектов
	$data = json_decode($_POST['neworder']);
	if (null == $data) {
		throw new Exception('Недопустимый формат');
	}
	//обновляем записи
	foreach ($data as $note) {
		$stmt->execute(array(':note_order'=>$note->order, ':id'=>substr($note->id, 5)));
	}
	$dbh = null;
	//отправляем отчет браузеру
	echo json_encode(array('status'=>'OK'));
} catch(Exception $e) {
	echo json_encode(array('status'=>'ERR', 'mes'=>'Ошибка: '.$e->getMessage()));
}

Здесь мы проверяем полученные данные и в цикле обновляем все записи. Используется обычный UPDATE запрос. Преобразование из JSON формата в PHP массив выполняется с помощью функции json_decode.

Как видите, пример получился довольно объёмный, но большая часть кода относится к различным проверкам. Поэтому, надеюсь, общую идею вы поняли 😉

Если у вас будут вопросы или замечания, пишите, буду рад обсудить!