Uma lista simples de tarefas usando WebDatabases HTML5

Introdução

Os bancos de dados da Web são novos no HTML5. Os bancos de dados da Web são hospedados e mantidos no navegador do usuário. Ao permitir que os desenvolvedores criem aplicativos com recursos avançados de consulta, prevê-se que surgirá uma nova safra de aplicativos da Web que poderão funcionar on-line e off-line.

O código de exemplo deste artigo demonstra como criar um gerenciador de listas de tarefas muito simples. É um passeio de alto nível por alguns dos recursos disponíveis em HTML5.

Pré-requisitos

Este exemplo usa um namespace para encapsular a lógica do banco de dados.

var html5rocks = {};
html5rocks.webdb = {};

Assíncrono e transacional

Na maioria dos casos em que você usa o suporte ao banco de dados da Web, a API assíncrona é usada. A API assíncrona é um sistema sem bloqueio e, portanto, não receberá dados por meio de valores de retorno, mas receberá os dados para uma função de callback definida.

O suporte ao banco de dados da Web por meio de HTML é transacional. Não é possível executar instruções SQL fora de uma transação. Há dois tipos de transações: transações de leitura/gravação (transaction()) e transações somente leitura (readTransaction()). Observação: as operações de leitura/gravação bloquearão todo o banco de dados.

Etapa 1. Como abrir o banco de dados

O banco de dados precisa ser aberto antes de ser acessado.
Defina o nome, a versão, a descrição e o tamanho do banco de dados.

html5rocks.webdb.db = null;

html5rocks.webdb.open = function() {
var dbSize = 5 * 1024 * 1024; // 5MB
html5rocks.webdb.db = openDatabase("Todo", "1", "Todo manager", dbSize);
}

html5rocks.webdb.onError = function(tx, e) {
alert("There has been an error: " + e.message);
}

html5rocks.webdb.onSuccess = function(tx, r) {
// re-render the data.
// loadTodoItems is defined in Step 4a
html5rocks.webdb.getAllTodoItems(loadTodoItems);
}

Etapa 2: Como criar uma tabela

Só é possível criar uma tabela executando um estado SQL CREATE TABLE dentro de uma transação.

Definimos uma função que criará uma tabela no corpo do evento onload. Se a tabela ainda não existir, será criada uma.

A tabela é chamada Atividade e tem três colunas.

  • ID: uma coluna de ID sequencial de incremento
  • Tarefas: uma coluna de texto que é o corpo do item
  • added_on: a hora em que o item de lista de tarefas foi criado
html5rocks.webdb.createTable = function() {
var db = html5rocks.webdb.db;
db.transaction(function(tx) {
tx.executeSql("CREATE TABLE IF NOT EXISTS " +
                "todo(ID INTEGER PRIMARY KEY ASC, todo TEXT, added_on DATETIME)", []);
});
}

Etapa 3. Como adicionar dados a uma tabela

Como estamos criando um gerenciador de listas de tarefas, é muito importante poder adicionar itens de atividades ao banco de dados.

Uma transação é criada. Dentro dela, um INSERT na tabela de tarefas pendentes é executado.

O executeSql usa vários parâmetros, o SQL para executar e os valores dos parâmetros para vincular a consulta.

html5rocks.webdb.addTodo = function(todoText) {
var db = html5rocks.webdb.db;
db.transaction(function(tx){
var addedOn = new Date();
tx.executeSql("INSERT INTO todo(todo, added_on) VALUES (?,?)",
    [todoText, addedOn],
    html5rocks.webdb.onSuccess,
    html5rocks.webdb.onError);
});
}

Etapa 4. Como selecionar dados de uma tabela

Agora que os dados estão no banco de dados, você precisa de uma função que recupere os dados. No Chrome, o banco de dados da Web usa consultas SQLite SELECT padrão.

html5rocks.webdb.getAllTodoItems = function(renderFunc) {
var db = html5rocks.webdb.db;
db.transaction(function(tx) {
tx.executeSql("SELECT * FROM todo", [], renderFunc,
    html5rocks.webdb.onError);
});
}

Observe que todos os comandos usados neste exemplo são assíncronos e, portanto, os dados não são retornados da transação ou da chamada executeSql. Os resultados são transmitidos para o callback de sucesso.

Etapa 4a. Renderizar dados de uma tabela

Depois que os dados forem buscados na tabela, o método loadTodoItems será chamado.

O callback onSuccess precisa de dois parâmetros. O primeiro é a transação da consulta, e o segundo é o conjunto de resultados. É bem simples iterar os dados:

function loadTodoItems(tx, rs) {
var rowOutput = "";
var todoItems = document.getElementById("todoItems");
for (var i=0; i < rs.rows.length; i++) {
rowOutput += renderTodo(rs.rows.item(i));
}

todoItems.innerHTML = rowOutput;
}
function renderTodo(row) {
return "<li>" + row.todo + 
        " [<a href='javascript:void(0);' onclick=\'html5rocks.webdb.deleteTodo(" + 
        row.ID +");\'>Delete</a>]</li>";
}

O efeito dessa chamada de método é que a lista de tarefas pendentes é renderizada em um elemento DOM chamado "todoItems".

Etapa 5. Excluir dados de uma tabela

html5rocks.webdb.deleteTodo = function(id) {
var db = html5rocks.webdb.db;
db.transaction(function(tx){
tx.executeSql("DELETE FROM todo WHERE ID=?", [id],
    html5rocks.webdb.onSuccess,
    html5rocks.webdb.onError);
});
}

Etapa 6. Como juntar tudo

Quando a página for carregada, abra o banco de dados, crie a tabela (se necessário) e renderize todos os itens de tarefas que já podem estar no banco de dados.

....
function init() {
html5rocks.webdb.open();
html5rocks.webdb.createTable();
html5rocks.webdb.getAllTodoItems(loadTodoItems);
}
</script>

<body onload="init();">

Uma função que obtém os dados do DOM é necessária. Portanto, chame o método html5rocks.webdb.addTodo

function addTodo() {
var todo = document.getElementById("todo");
html5rocks.webdb.addTodo(todo.value);
todo.value = "";
}