Создание списка дел (To-Do лист) средствами jQuery и Web SQL Database

Здравствуйте, уважаемые читатели XoZbloga! В HTML5 есть много новых возможностей, которые расширяют границы для творчества программистов. Одной из таких возможностей является создание локальной базы данных (когда данные хранятся на клиенте, то есть в браузере посетителя) — Web SQL Database. В этом уроке создадим список дел как его еще называют To-Do лист, с помощью данной технологии и jQuery.
Прежде чем перейти к описанию кода, стоит упомянуть о поддержке Web SQL браузерами, на данный момент эта технология работает c:

  • Chrome 4+
  • Safari 4+
  • Opera 11+
  • iOS Safari 5+
  • Android 3+
  • Opera Mobile 11+

Будем надеяться, что в скором будущем остальные браузеры сократят отставание в этом вопросе.

Вот, что должно получиться в итоге:

Список дел с помощью Web Sql Database

Основные методы Web SQL

Мы будем работать с тремя основными методами, предоставляемыми Web SQL API, чтобы реализовать наш Список Дел:

  • openDatabase — этот метод будет создать экземпляр объекта базы данных, если такая БД существует, иначе создаст новую.
  • transaction — этот метод позволяет совершать транзакции с базой данных.
  • executeSql — позволит нам запускать SQL запросы, такие как читать, вставлять и удалять записи.

Пример работы с методами

openDatabase

1
openDatabase("speckyboy","1.0","Моя первая БД",5 * 1024 * 1024);

Данный метод имеет 4 параметра разделенных запятыми:

  • speckyboy: Название базы данных.
  • 1.0: Версия БД.
  • Моя первая БД: Описание БД.
  • 5*1024*1024: Размер БД равный 5мб.

transaction

1
2
3
db.transaction(function (tx) {
    // здесь находятся SQL запросы
});

transaction, необходима для выполнения различных SQL-запросов, принимает один параметр, который будет добавляться к фактическому запросу.

executeSql

1
tx.executeSql('CREATE TABLE IF IT DOES NOT EXIST todo (id INTEGER, foo TEXT)');

Вот один из примеров SQL запроса. Происходит запрос на создание таблицы todo, если таковой еще не существует в базе. Теперь можно перейти непосредственно к созданию «списка дел».

HTML разметка

Для работы нам понадобится библиотека jQuery, а также jQuery User Interface (для создания удобного календарика выбора даты). Поэтому подключаем их к индексной странице:

1
2
3
4
5
6
<!-- Библиотека jQuery -->
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script>
<!-- jQuery User Interface -->
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.min.js"></script>
<!-- CSS для календаря -->
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.17/themes/redmond/jquery-ui.css" type="text/css">

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div id="bodyWrapper">
   <div id="todo_wrapper" class="white_bg">
       <h2>Список дел</h2>
       <!-- В этот список будут добавлены элементы (созданные задания/дела) -->
       <ul class="list"></ul>
    </div>
    <!-- Форма для добавления задания -->
    <div id="todo_form" class="white_bg">
       <div id="form_wrapper">
       <!-- Текстовая область -->
       <textarea id="todo_item_text" placeholder="Что нужно сделать..."></textarea>
       <!-- Дата -->
       <input type="text" id="todo_due_date" placeholder="Установить дату..." />
    </div>
       <!-- Кнопка добавить -->
       <input type="submit" id="create_todo" value="Добавить" class="button"/>
    </div>
</div>

Чтобы не терять времени, приводить CSS стили не буду. Так как особой роли они не играют. Поэтому сразу переходим к работе с базой данных.

Работа с Web SQL

Как Вы знаете, HTML5 все еще находится в развитии и работает не во всех браузерах. В результате, нам нужно написать функцию, чтобы выяснить, работает ли браузер пользователя с Web SQL. Если браузер не поддерживает Web SQL, мы покажем ошибку.

Весь нижеследующий код находится domReady функции:

1
2
3
$(function(){
      // Внутри этой domReady функции находится весь код  
});

Функция проверка браузера на возможность использования Web SQL:

1
2
3
4
5
6
7
8
function init() {
    if(typeof(openDatabase) !== 'undefined')
    { // позже здесь появится код }
    else
    { $('#bodyWrapper').html('<h2 class="error_message">Ваш браузер не поддерживает webSql</h2>'); }
}
// Вызываем эту функцию
init();

Если браузер поддерживает работу с локальными БД значить будут выполняться функции создания таблицы и загрузки данных (о них позже), иначе показываем ошибку (в блок div #bodyWrapper с помощью метода .html вносим текст ошибки). Для того чтобы проверить ее работоспособность откройте index.html в Firefox.

Кроме того, мы создали 3 переменных с использованием пространств имен, которые будут NULL по умолчанию.

1
2
3
var speckyboy = {}
speckyboy.init = {}
speckyboy.init.db = {}

Пространство имен используется для предотвращения конфликтов имен переменных в будущем.

Создание БД

Функция создания локальной базы данных:

1
2
3
4
5
// Для удобства помещаем функцию в глобальную переменную
speckyboy.init.open = function(){
speckyboy.init.db = openDatabase("speckyboy","1.0","Моя первая БД",1024*1024*5);
// название БД, версия, описание, размер
}

Создание таблицы в БД

После создания базы данных, необходимо создать таблицу, в которую будут помещаться данные:

1
2
3
4
5
6
speckyboy.init.createTable = function(){
     var database = speckyboy.init.db;
     database.transaction(function(tx){
     tx.executeSql("CREATE TABLE IF NOT EXISTS todo (ID INTEGER PRIMARY KEY ASC,todo_item TEXT,due_date VARCHAR)", []);
     });
}

Эту функцию также помещаем в переменную. Создаем таблицу todo с тремя полями:
ID: первичный ключ, который будет автоматически увеличиваться всякий раз при добавлении новой записи.
todo_item: текстовое поле с названием введенного задания.
due_date: поле varchar с датой.

Заполнение таблицы

База создана, таблица создана теперь можно переходить к ее заполнению. Для этого также создаем отдельную функцию, которую помещаем в переменную. У этой функции есть 2 параметра: название задания (todoItem) и дата (dueDate):

1
2
3
4
5
6
7
8
9
10
11
speckyboy.init.addTodo = function(todoItem,dueDate){
     // Подключаемся к базе
     var database = speckyboy.init.db;
     // Инициализируем транзакцию
     database.transaction(function(tx) {
     // Выполняем SQL запрос на добавление записи в таблицу
     tx.executeSql("INSERT INTO todo (todo_item,due_date) VALUES (?,?)", [todoItem,dueDate],
     // Размещаем данные на странице (подробно о функции немного позже)
     showAllTodo(todoItem,dueDate));
  });
}

Данная функция вызывается после нажатия на кнопку добавить, далее обработчик этого события:

1
2
3
4
5
6
7
8
9
10
11
12
$('#create_todo').click(function(){
var todo_item_text = $('#todo_item_text').val();
var todo_due_date = $('#todo_due_date').val();
   
   if(todo_item_text.length == '' || todo_due_date.length == '') {
       alert('Заполните все поля!');
   } else {
       speckyboy.init.addTodo(todo_item_text,todo_due_date);
       $('#todo_item_text').val('');
       $('#todo_due_date').val('');
   }
});

Давайте по-порядку:

  • C помощью селектора отслеживаем клик по кнопке добавить (#create_todo);
  • Создаем несколько переменных и опять таки же с помощью селекторов отбираем наши поля с названием и датой, вытаскиваем значения и помещаем их в эти переменные;
  • Проверяем не пусты ли эти переменные, если нет значит вызываем функцию speckyboy.init.addTodo с параметрами (название и дата задания);
  • После чего очищаем поля на странице.

Тестирование

Уже можно проверить результат нашего кодирования. Наглядней всего это сделать в Chrome.


Локальная база данных в Chrome

Правой кнопкой мыши — Просмотр кода элемента — Вкладка Ресурсы (или F12). Здесь мы можем видеть все локальные БД и внесенные в них данные.

Получение данных из БД

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
speckyboy.init.getTodo = function(){
   var database = speckyboy.init.db;
   database.transaction(function(tx){
       // запрос на выборку данных
       tx.executeSql("SELECT * FROM todo", [], function(tx,result){
           // до тех пор пока есть данные
           for (var i=0; i < result.rows.length; i++) {
               // Присваиваем их переменным
               todo_item = result.rows.item(i).todo_item;
               todo_due_date = result.rows.item(i).due_date;
               todo_id = result.rows.item(i).ID;
               // вызываем функцию размещения данных на странице
               showAllTodo(todo_item,todo_due_date,todo_id);
           }
       });
   });
}

Данная функция позволяет получить данные из таблицы todo. Снова подключаемся к БД, инициализируем транзакцию и выполняем запрос на выборку данных. После чего в цикле полученные данные передаем функции showAllTodo, которая добавляет элементы ul списка на странице, с нашими данными.

А вот и сама функция showAllTodo:

1
2
3
4
5
6
function showAllTodo(todo_item,todo_due_date,todo_id){
   $('ul.list').append('<li><div class="todo_item"><span class="todo_text">' + todo_item + '</span>' +
   '<a href="#" id="delete"> Удалить </a><span class="due_date">' + todo_due_date + '</span>' +
   '<input id="this_id" value="' + todo_id + '" type="hidden"><div class="clear"></div></div></li>');
   $('li:last').addClass('highlight').delay(1000).queue(function(next){ $(this).removeClass('highlight');    next(); });
}

Селектором выбираем список ul, после чего методом .append добавляем новый элемент списка с полученными данными. А также подсвечиваем (добавляем к элементу li css класс highlight ) желтым цветом, только что созданный элемент. По прошествию 1-ой секунды удаляем этот класс. Ключевым здесь помимо данных является еще и то, что к каждой записи мы добавляем скрытое поле (input hidden) со значением равным идентификатору этой записи. Это нам понадобиться при удалении.

Теперь можно вернуться к первой функции init(), которая вызывается сразу при заходе на страницу и добавить в нее не достающий код:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Объявляем функцию
function init(){
   if(typeof(openDatabase) !== 'undefined')
   {
      // Создаем подключение к БД или создаем новую
      speckyboy.init.open();
      // Создаем если необходимо таблицу
      speckyboy.init.createTable();
      // Получаем данные из таблицы
      speckyboy.init.getTodo();
   }
   else
   {
      $('#bodyWrapper').html('<h2 class="error_message"> Ваш браузер не поддерживает технологию Web SQL </h2>');
   }
}
// Вызываем функцию init
init();

Удаление записей из БД

1
2
3
4
5
6
speckyboy.init.deleteTodo = function(id){
    var database = speckyboy.init.db;
    database.transaction(function(tx){
        tx.executeSql("DELETE FROM todo WHERE ID=?",[id]);
     });
}

Удалить запись из таблицы довольно просто. Все, что нам нужно сделать, это передать идентификатор записи который мы хотим удалить. Теперь нам нужно написать обработчик щелчка, который будет реагировать на каждый клик по кнопке удалить.

Вот это событие:

1
2
3
4
5
6
$('#delete').live("click",function(){
var id = $(this).closest('li').find('#this_id').val();
$(this).closest('li').addClass('highlight').delay(1000).queue(function(next){ $(this).remove(); next(); });
// вызываем функцию удаления с параметром идентификатор записи
speckyboy.init.deleteTodo(id);
});

Отслеживаем событие клик по одной из кнопок удалить. Так как кнопка «удалить» расположена в пределах элемента списка li, то мы используем метод .closest чтобы найти ближайший родительский элемент li, а в нем скрытое поле. В переменную id помещается идентификатор записи, который находится в значение скрытого поля.

На этом работу с Web SQL можно считать завершенной. Нам осталось настроить только календарик. Здесь все просто, ведь мы используем готовый набор пользовательского интерфейса. Все что нам остается вызвать метод datePicker и русифицировать календарь (используя некоторые опции):

1
2
3
4
5
6
7
8
9
10
$('#todo_due_date').datepicker({
"dateFormat":"dd.mm.yy",
"dayNamesMin":["Вс","Пн","Вт","Ср","Чт","Пт","Сб"],
"dayNames":["Воскресенье","Понедельник","Вторник","Среда","Четверг","Пятница","Суббота"],
"firstDay":"1",
"monthNames:["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь",
"
Ноябрь","Декабрь"],
"
nextText":"Следующий",
"
prevText":"Предыдущий"
});

Чтобы оставаться в курсе свежих статей и уроков подписывайтесь на страницу ВКонтакте или добавляйте в круги на Google+. Не забывайте оставлять комментарии, спасибо!

Чтобы оставаться в курсе свежих статей и уроков подписывайтесь на еженедельную почтовую рассылку или на новостную ленту RSS. Спасибо!