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 de consulta avançados, espera-se que uma nova geração de aplicativos da Web surja com a capacidade de funcionar on-line e off-line.

O exemplo de código neste artigo demonstra como criar um gerenciador de listas de tarefas muito simples. É um tour de alto nível sobre alguns dos recursos disponíveis no HTML5.

Pré-requisitos

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

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

Assíncrona e transacional

Na maioria dos casos em que você usa o suporte ao banco de dados da Web, você usa a API assíncrona. A API assíncrona é um sistema não bloqueador e, como tal, não recebe dados por valores de retorno, mas sim dados enviados para uma função de callback definida.

O suporte ao banco de dados da Web pelo 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 de leitura (readTransaction()). A transação de leitura/gravação bloqueia todo o banco de dados.

Etapa 1. Como abrir o banco de dados

O banco de dados precisa ser aberto antes de ser acessado.
É necessário definir 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 uma instrução SQL CREATE TABLE em uma transação.

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

A tabela é chamada de "todo" e tem três colunas.

  • ID: uma coluna de ID sequencial incremental
  • tarefa: uma coluna de texto que é o corpo do item
  • added_on: a hora em que o item de tarefa 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

Estamos criando um gerenciador de listas de tarefas. Por isso, é muito importante que possamos adicionar itens de tarefas ao banco de dados.

Uma transação é criada e, dentro dela, um INSERT na tabela todo é realizado.

executeSql recebe vários parâmetros, o SQL a ser executado e os valores de 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 os extraia. No Chrome, os bancos de dados da Web usam 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);
});
}

Todos esses 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 da tabela, o método loadTodoItems será chamado.

O callback onSuccess usa dois parâmetros. A primeira é a transação da consulta, e a segunda é o conjunto de resultados. É bastante 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 é renderizada em um elemento DOM chamado "todoItems".

Etapa 5. Como 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 conectar tudo

Quando a página carregar, abra o banco de dados e crie a tabela (se necessário) e renderize os itens de tarefas que já estiverem no banco de dados.

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

<body onload="init();">

Uma função que extrai 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 = "";
}