Управление табличными данными при помощи jQuery

jQuery

Update: Внимание! Эта статья устаревшая, а плагин, который здесь используется уже не поддерживается автором и имеет неисправленные ошибки.

В одной из прошлых статей я писал о том, как сделать текст на странице динамически редактируемым. Там был представлен метод редактирования при помощи плагина jEditable. Таким образом можно динамически редактировать любой блок текста на странице. Однако если речь идет о табличных данных, то гораздо удобнее использовать другое решение – плагин tableFormSynch. Этот плагин связывает таблицу с формой, давая возможность динамически редактировать данные в таблице, а также добавлять и удалять записи.

В этой статье я покажу, как сделать простое приложение, реализующее редактирование, добавление и удаление записей таблицы, сохраняя данные при помощи AJAX. Чтобы создать приложение нам будут нужны библиотека jQuery, плагин metadata (требуется для работы плагина tableFormSynch), а также jQuery Form Plugin для сохранения данных формы через AJAX. Но прежде чем мы начнем, предлагаю посмотреть на готовый результат. Смотреть демо пример.

Итак, начинаем с того, что создаем HTML страницу и подключаем к ней необходимые нам скрипты:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="ru-RU">

<head profile="http://gmpg.org/xfn/11">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

<script type="text/javascript" src="jquery-1.2.6.min.js"></script>
<script type="text/javascript" src="jquery.metadata.min.js"></script>
<script type="text/javascript" src="jquery.tableFormSynch.documented.js"></script>
<script type="text/javascript" src="jquery.form.js"></script>

</head>
<body>

</body>
</html>

Далее добавляем табличные данные, которые мы собираемся редактировать, плюс сюда же добавляем ссылки на редактирование и удаление записи. Здесь есть обязательные условия: для каждой строки таблицы нужно указать ID записи в атрибуте id и метаданные (то есть все данные записи) в атрибуте class. И еще – все строки таблицы должны быть обязательно заключены в тэги <tbody>:

<tr id="1" class="{personId:1,first_name:'Иван',last_name:'Иванов',position:'Программист'}">
	<td>Иван</td>
	<td>Иванов</td>
	<td>Программист</td>
	<td><a href="#" class="edit">Редактировать</a> | <a href="#" class="delete">удалить</a></td>
</tr>

Следующий шаг – создание формы: она будет располагаться в последней строке таблицы и при загрузке страницы будет не видна. Появляться она будет по надобности, при нажатии на ссылки “добавить запись” или “редактировать”. Форма будет иметь все нужные поля (в нашем случае текстовые поля) и три кнопки – “добавить” и “редактировать”, которые появляются в зависимости от выбранного действия, а также “отмена”, по нажатию на которую форма будет исчезать.

<form id="rowEditForm" action="save.php" method="post">
<table width="100%" cellpadding="0" cellspacing="0" border="0" id="demoTable" class="tablesCorp">

<!-- строки таблицы -->

<tr id="editableRow">
	<td><input type="hidden" name="personId" value="0"/><input type="text" name="first_name" value=""/></td>
	<td><input type="text" name="last_name" value=""/></td>
	<td><input type="text" name="position" value=""/></td>
	<td>
		<input id="updateBtn" type="submit" name="update" value="Обновить"/>
		<input id="addBtn" type="submit" name="add" value="Добавить"/>
		<input id="cancelBtn" type="button" name="cancel" value="Отмена"/>
		<img id="loading" src="loading.gif" />
	</td>
</tr>
</tbody>
</table>
</form>

Ну и самая малость – под таблицей размещаем ссылку “добавить запись”:

<a href="#" class="add">Добавить запись</a>

Теперь приступим к созданию скрипта нашего приложения. Как полагается для скриптов, написанных под jQuery, заключаем весь наш код в функцию $.ready(), и первое, что мы туда поместим, это вызов функции bindTableToForm(), которая связывает таблицу с формой:

$(document).ready(function() {

	$("#demoTable").bindTableToForm($("#rowEditForm"),"personId");

});

Первым параметром в функцию мы передаем форму, а вторым – название ключевого поля записи, в нашем случае это ID пользователя.

Далее, создаем фукнцию редактирования. Добавляем ко всем ссылкам “редактировать” обработчик, который будет показывать форму редактирования под нужной строкой. Форму заполняем данными при помощи функции populateForm()и здесь же показываем конпку “редактировать” и прячем конпку “добавить”. Таким образом мы переводим форму в режим редактирования. Ну и для красоты подкрашиваем редактируемую строку бледно розовым цветом:

$("a.edit").click(function() {

	$("#addBtn").hide();
	$("#updateBtn").show();

	$(this).populateForm();

	var row = $(this).parent().parent();
	row.find('td').css('background-color','#faa');
	$('#editableRow').insertAfter(row).fadeIn('slow');

	// отмена действия по умолчанию
	return false;
});

При нажатии на кнопку “обновить”, данные формы будут отправляться на сервер через AJAX, и при успешном сохранении, запись в таблице будет обновляться. Выполняем это все в обработчике onclick кнопки:

$("#updateBtn").click(function() {
	$('#rowEditForm').ajaxForm({
		beforeSubmit : function(){
			$('#loading').show();
		},
		success : function(response){
			$('#loading').hide();
			if (response == 1)
				$("#rowEditForm").updateRow();
			else
				alert('Ошибка сохранения данных');

			var rowId = $("input[name='personId']").val();
			var row = $('tr#'+rowId).find('td').css('background-color','#F5F5F5');
			$('#editableRow').fadeOut('slow');
		}
	});
});

Здесь мы используем функцию ajaxForm() для выполнения AJAX запроса с данными формы. При успешном сохранении данных, сервер возвращает значение 1, в любом другом случае, трактуем результат как ошибку. Данные в таблице обновляем фукнцией updateRow().

Далее реализовуем добавление новой записи. Всё делаем также, как и для обновления, только вместо того, чтобы заполнять форму, очищаем её функцией clearForm(). Ну и естественно, вместо кнопки “редактировать” делаем активной кнопку “добавить”:

$("a.add").click(function() {
	$("#addBtn").show();
	$("#updateBtn").hide();

	// очищаем форму
	$("#rowEditForm").clearForm();
	$("input[name='personId']").val(0);

	$('#demoTable tbody').append($('#editableRow'));
	$('#editableRow').fadeIn('slow');

	return false;
});

Обработчик для кнопки “добавить” также мало чем отличается от функции обновления, за исключением того, что сервер возвращает ID новой записи, который затем передается в функцию addRow() для добавления записи:

$("#addBtn").click(function() {
	$('#rowEditForm').ajaxForm({
		beforeSubmit : function(){
			$('#loading').show();
		},
		success : function(response){
			$('#loading').hide();
			if (response == 0)
				alert('Ошибка добавления данных');
			else
				$("#rowEditForm").addRow(response);

			$('#editableRow').fadeOut('slow');
		}
	});
});

Теперь выполним удаление записи – используем для этого функцию deleteRow(). Для отправки запроса на сервер будем использовать функцию $.post(), которая будет отправлять запрос в отдельный файл delete.php. Последний выполняет удаление записи и возвращает 1 если запись удалилась, и 0 если произошла ошибка. В самом начале функции мы получаем ID записи которую необходимо удалить, затем передаем это значение в функцию $.post() в качестве параметра personId, который будет установлен переменной в POST:

$("a.delete").click(function() {

	var id = $(this).parent().parent().attr('id');

	var that = $(this);
	$.post('delete.php',
		{personId : id},
		function(data){
			if (data == 1)
				that.deleteRow();
			else
				alert('Ошибка удаления записи');
		});
	return false;
});

Ну и последняя, самая простая функция – “отмена”. Здесь мы просто прячем форму и закрашиваем все строки формы в стандартный цвет:

$("#cancelBtn").click(function(){
	$("#editableRow").fadeOut("slow");
	$(".tablesCorp td").css('background-color','#F5F5F5');
});

Посмотреть скрипт полностью можно здесь.

После этого нужно еще установить пару обязательных стилей:

#editableRow {display:none}
#addBtn {display:none}

Первая строка прячет форму редактирования, а вторая кнопку “добавить”, которые в начале работы должны быть скрытыми.

Вот и все, наше приложение готово. Буду рад услышать Ваши замечания :)

До встречи!

Update: Внимание! Эта статья устаревшая, а плагин, который здесь используется уже не поддерживается автором и имеет неисправленные ошибки.

смотреть демоскачать демо

Maklay.com - Большой каталог товаров для спорта и активного отдыха
  • http://physics.com.ua/ Stepler

    надо бы при нажитие на удаление сделать подтверждение. а то бывает нечаянно нажал и вот ))) например, alert(’действительно удалить запись?’)……

  • admin

    @Stepler
    Да и правда нужно ). Вот так бывает – все сделаешь, а про элементарное забудешь…

  • http://www.aos.com.ua nice

    я вот не использую alert, просто показываю скрытый DIV у которого ОК – отправить запрос, а ОТМЕНА – скрыть DIV…

  • http://mabp.kiev.ua/2009/01/25/linkdump-3/ Linkdump #3 | CTAPbIu_MABP’s BLOG

    [...] освоил Управление табличными данными при помощи jQuery… много [...]

  • BIH

    It would be good to add to the example the ’save.php’ and ‘delete.php’ scripts, otherwise it doesn’t work !

  • admin

    @BIH
    Oops… Thank you. I forgot about this two :(
    Fixed.

  • Дмитрий

    какреализовать это с подключением к БД????ктонить подскажет?

  • admin

    @Дмитирй
    Скрипт выполняет AJAX запрос к save.php или delete.php, а там уже выполняете сохранение либо удаление стандартными средствами. К примеру на PHP:
    mysql_query(’update some_table set name = ‘.$value);

  • Дмитрий

    а подгрузка данных в талицу, здесь данные заданы прям в html ведь….

  • admin

    Да, тут данные не подгружаются, они сразу целиком в таблице выводятся. Но можно в принципе попробовать объединить с пагинатором, там можно динамически подгружать: http://www.jstoolbox.com/2008/10/20/postranichnaya-navigaciya-na-jquery/

  • http://seo-expa.ru mr.codec

    Спасибо большое!!!!!!! Офигенный материал по jquery! с таблицами как раз полдня думаю как покрасивее соорудить. Возьму ваш пример, и заточу под БД. респект за статью

  • Димон

    Неплохо было бы на при удалении записи добавить подтверждение, гы гы гы

  • дмитрий

    здорово, очень полезный урок…

    только одна проблема…
    все работает кроме функций
    $(”#rowEditForm”).updateRow(); и
    $(”#rowEditForm”).addRow(response);

    updateRow – вообще не обновляет запись, а addRow добавляет не только что добавленную запись а первую запись из таблицы… Причем реально запись в базу добавляется и response 1…

    нет мыслей, в чем может быть дело?

    спасибо

  • admin

    @дмитрий
    Затрудняюсь ответить наверняка, скорее всего проблема с неверным ID строки. Проверьте, правильно ли вы передаете его.

  • дмитрий

    а откуда ID строки попадает в эти функции? из класса?

  • admin

    При создании новой записи, серверный скрипт возвращает ID новой строки. Посмотрите в демо пример, аякс запрос возвращает {response : 1234} – это значение и есть id новой записи. Оно затем устанавливается в виде id: <tr id=”1234″ …..>

  • Илья

    У меня та же проблема. id ставит правильный – который получает от скрипта. А вот содержимое полей для новой записи берет не из полей ввода, а из первой строки (заголовки колонок).

  • wdr

    с id у меня проблем нет, разобрался, есть вопрос по добавлению поля с select, оно добавляется не сложно, но возникает трудность с обновлением после сохранения записи, только в этом поле остается старое значение, может в контексте статьи рассмотреть пример шире

  • Sparco

    Интересно получилось ли у Дмитрия замутить это все под БД ? Если у админа есть пример заточен под БД пожалуйста выложите, буду очень благодарный. А то самому не получилось :(

  • Sparco

    Помогайте мужики, вот как я сделал:

    \\ Подключение к базе \\

    Имя
    Фамилия
    Должность

    <?php
    while($row = mysql_fetch_array($result))
    {
    echo ”
    ” . $row['section'] . ”
    ” .$row['area'] . ”
    ” . $row['price'] . ”
    <a href=’#’ rel=”nofollow”>Редактировать</a> | <a href=’#’ rel=”nofollow”>удалить</a>
    “;
    }
    ?>

    <a href=”#” rel=”nofollow”>Добавить запись</a>

    Файл save.php выглядит следующим образом:

    Но нифига не обновляет поскольку какое нужно ставить $value ??? И как вообще должен выглядеть этот save.php ?

  • admin

    @Sparco
    В моем примере при отправке AJAX запроса передаются следующие параметры: first_name, last_name, position, т.е. по названиям полей формы. Если у вас другие поля, то подставьте соответсвенно свои значения. Далее сохраняются данные в базе. Если это новая запись, то personId (идентификатор поля равен нулю), занчит выполняем вставку:
    mysql_query(’insert into mytable (first_name, last_name, position) values (’.mysql_real_escape_string($_REQUEST['first_name']).’ …… и так далее ‘);
    и тут же получаем и возвращаем ID созданной записи, которую возвращаем скрипту:
    echo mysql_insert_id(); exit;

    Если это обновление, то выполняем его для уже имеющейся записи (personId у нас в этом случае больше нуля):
    mysql_query(’update mytable set first_name = “‘.mysql_real_escape_string($_REQUEST['first_name']).’” ….. и т.д…. where person_id = ‘.intval($_REQUEST['personId'])

    Вот примерно так.

  • Sparco

    @admin
    спасибо за ответ, но почему то не работает :( делаю так:
    файл save.php выглядит так:

    //var_dump($_POST);
    sleep(1);

    if ($_POST['personId'] == 0) {
    echo rand(100, 100000);

    /* $data = array(
    ‘personId’ => 3,
    ‘first_name’ => $_POST['first_name'],
    ‘last_name’ => $_POST['last_name'],
    ‘position’ => $_POST['position']
    );
    echo json_encode($data);*/
    } else {
    echo 1;

    \\ ПОДКЛЮЧЕНИЕ К БАЗЕ

    mysql_query(”update v0 set first_name = ‘”.mysql_real_escape_string($_REQUEST['first_name']).”‘ WHERE person_id = `”.intval($_REQUEST['personId'])”` “);
    }

    Но выкидывает алерт “Ошибка сохранения данных” проверьте пожалуйста мой запрос правильно ли я его отредактировал. И если у вас есть пожалуйста дайте свой пример с дампом базы. Буду ОЧЕНЬ благодарен.

  • Twil

    /*
    все работает кроме функций
    $(”#rowEditForm”).updateRow(); и
    $(”#rowEditForm”).addRow(response);
    */
    Да, тоже битый час сегодня на это потратил, озарение снизошло, только когда в tableFormSynch залез (ну а чуть позже – сверился с исходником примера). В статье во второй вставке кода (про задание существующих рядов таблицы) указано, что данные должны быть перечислены в className TR-ки, но опущено, что для каждой TD-шки должен быть также указан класс (для “Иван” – first_name, для “Иванов” – last_name, для “Программист” – position). Иначе tableFormSynch.updateRow() их найти не может.

  • http://mgvs.org alexlp

    Пришлось отказаться от скрипта, ибо если удалить все пункты, новый не добавляется (

  • Wombat

    /*
    Пришлось отказаться от скрипта, ибо если удалить все пункты, новый не добавляется (
    */

    Это происходит из-за того, что AddRow клонирует первую строку таблицы после тега . А так как ее нет, ничего не добавляется.
    Исправить можно следующим образом:
    1. Добавляем “нулевую” строку после и скрываем ее через style=”display:none;”
    2. Обнуляем ID (например, id=”-1″, но не 0!)
    3. В скрипт в обработчик класса #addBtn после вызова AddRow добавляем
    $(’tr#’+response).show();
    Это нужно, чтобы отобразить скрытую строку.
    При желании можно автоматизировать процесс создания скрытой нулевой строки при запуске скрипта.

  • Pavel

    Да, тож ковырялся, но ничего не вышло, муть какая то

  • Wombat

    У меня все работает как часики. Кроме того я скрываю все остальные элементы управления (добавить/удалить) после нажатия ссылки/кнопки и запрашиваю подтверждение при удалении.

  • TEvGenius

    Плагин довольно интересный, но не доработан полностью. Из основных багов – добавление записи “с нуля”, т.е. если все записи удалить, и попробовать добавить новую, то получится довольно таки интересный эффект. Вообще его надо дорабатывать. Если кто знает альтернативу этому плагину, то с удовольствием рассмотрел бы. Еще к работе с базами данных, работает на ура! Даже ничего толком править не надо, главное чтоб скрипты save.php и delete.php возвращали нормальные ответы. Так при добавлении записи, как было сказано выше, скрипт должен вернуть ID последней записи, при обновлении и удалении просто 1. Ну а впрочем, можно плагин подделать и под свои конкретные нужды.
    Спасибо за статью!

  • GooD][Man

    демо – не работает в Opera 10.0

  • Igor

    Никак не могу понять как сделать save файл. Может кто-то может выложить его полностью?
    Спасибо

  • admin

    Для начала напомню – у скрипта есть неприятный недостаток (смотрите выше): “Пришлось отказаться от скрипта, ибо если удалить все пункты, новый не добавляется…”. А файл save примерно следующий:
    if ($_POST['personId'] == 0) {
    $data = array(
    ‘first_name’ => $_POST['first_name'],
    ‘last_name’ => $_POST['last_name'],
    ‘position’ => $_POST['position']
    );
    // Добавляем запись в базу данных, затем извлекаем ID добавленой записи и возвращаем его
    // …
    echo $lastInsertId;
    } else {
    // Обновляем существующую запись по ID ($_POST['personId'])
    // и возвращаем 1 как знак того, что запись сохранена
    echo 1;
    }

  • http://dobryjhosting.ru Babiy

    А подскажите пожалуйста как всё же заставить этот плагин подгружать табличные данные из базы, просто у меня там после обновляются некоторые поля и нужно что бы результат обновления виден был (обновляются в файле save.php другими словами там расчёт происходит по получиным из плагина данным меняются другие данные в базе) а плагин не хочет подгружать эти данные, приходится обновлять страничку поновой, может есть решения как это организовать, или хотябы заставить страницу перезагрузится в автомате?

  • admin

    Это сложно сделать. Если у вас после сохранения обновляются сразу несколько строк, то AJAX по-моему лучше не использовать.

  • http://dobryjhosting.ru Babiy

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

    Вот мой файл save.php

    $sql=”SELECT * FROM “.$db->prefix(’shop_zayavka’).” WHERE id=’”.$HTTP_POST_VARS['pid'].”‘”;
    $res=$db->query($sql);
    $up=$db->fetch_array($res);
    $upak=$up['zakupka']/$up['upakovok'];
    $zakupka=$upak*$HTTP_POST_VARS['upakovok'];
    $upakovok=$HTTP_POST_VARS['upakovok'];
    $summa=$zakupka*$up['cena'];
    $sql=”UPDATE “.$db->prefix(’shop_zayavka’).” SET
    zakupka=’$zakupka’
    , upakovok=’$upakovok’
    , summa=’$summa’ WHERE id=’”.$HTTP_POST_VARS['pid'].”‘”;
    $db->query($sql);
    echo ‘1′;

  • admin

    В таком случае нужно скрипт изменять так, чтобы он мог принимать JSON или XML от сервера. Соответственно сервер должен эти данные (значения столбцов) возвращать вместо echo 1.

  • http://dobryjhosting.ru Babiy

    Спасибо большое будем копать…

  • Valey

    Народ а как проверку удаления сделать. Пытался confirmom он переменные е получает ковырялся в script.js тоже не пашет. =(

  • http://uspeh.uz Ильмир

    ADMIN не мучай людей, помоги нам )

  • Сергей

    Помогите, пожалуйста, с файлом save/
    Вот мой вариант:
    $_POST['service'],
    ‘last_name’ => $_POST['last_name'],
    ‘position’ => $_POST['position']
    );
    // Добавляем запись в базу данных, затем извлекаем ID добавленой записи и возвращаем его
    mysql_query(’update table set service = “‘.mysql_real_escape_string($_REQUEST['service']).’” where person_id = ‘.intval($_REQUEST['personId'])
    echo $lastInsertId;
    } else {
    // Обновляем существующую запись по ID ($_POST['personId'])
    // и возвращаем 1 как знак того, что запись сохранена
    echo 1;
    }
    ?>
    Выдаёт ошибку записи данных.

  • admin

    Трудно что-то понять, в комментарии написано:
    // Добавляем запись в базу данных…
    а в запросе идет
    update table set service = …
    Table это имя таблицы такое?
    Откуда берется $lastInsertId?

  • Сергей

    Это я всё взял из Вашего примера.
    Покажите, пожалуйста, на готовом примере, как при добавлении новой записи, скажем, Александр, в таблицу table в поле service оно записывалось.
    Именно файл save. С обычными запросами работаю уверенно, а тут вообще всё для меня новое. Скрипт учень хороший, как раз то, что нужно, только помогите разобраться до конца.

  • admin

    insert into my_table set service = ‘my_value’ where person_id = 1;
    Если опять будет выдавать ошибку, посмотрите, какая именно ошибка:
    mysql_error();

  • Сергей

    Вот мой файл save:
    $_POST['service'],
    ‘last_name’ => $_POST['last_name'],
    ‘position’ => $_POST['position']
    );
    mysql_query(”insert into table set service = ’service’ where person_id = 1;”)
    echo $lastInsertId;
    } else {
    echo 1;
    }
    ?>
    Так должно быть?
    При добавлении новой записи просто добавляется Иван Иванов, что бы ни ввёл. Ошибки нет.

  • Сергей

    Файл добавляется неполностью, много фильтр отрезает…

  • Юрий

    Разобрался. Все работает, в том числе подгрузка таблицы из БД и сохранение в БД и добавление новой строки с “нуля” (Спасибо всем за комментарии). Проблема стала с реализацией выпадающего списка: список выводится в таблицу и даже сохраняется в БД значение value (напр. jena), но не возвращается обратно в таблицу название выбранного пункта (напр. жена).

    муж
    жена
    сын
    дочь

    Помогите пожалуйста. Очень нужно.

  • Стас

    А подскажите пожалуйста как сделать, чтоб новая строка появлялась сверху таблицы, а не с низу ? Где вообще копать ?

  • admin

    @Стас
    У меня, для добавления строки используется append(), а поместить сверху можно при помощи insertBefore(), prepend(), prependTo().
    Пример:
    $(’.my_table’).prepend(row);

  • Стас

    @admin
    Спасибо огромное! =)

JSToolbox создан на основе WordPress