Construire une app basique avec Indexeddb

Pour ce tutoriel, je me suis inspiré de celui-ci : Build a basic web app with IndexedDB

Si vous comprenez l'anglais, ce tutoriel constitue de loin la meilleure introduction à IndexedDB que j'ai trouvée. Je n'en ferai pas une traduction littérale, mais une adaptation libre.

Pour de plus amples informations veuillez vous référer au document de référence de l'API d'IndexedDB.

Cf.

https://developer.mozilla.org/fr/docs/Web/API/API_IndexedDB

Vous trouverez aussi un tutoriel plus complet à cette adresse : https://developer.mozilla.org/fr/docs/Web/API/API_IndexedDB/Using_IndexedDB

Introduction

IndexedDB est une base de données qui permet de stocker de grande quantité de données dans le navigateur d'un utilisateur, de manière persistante. Et ainsi ouvre la possibilité de créer une application complète à partir d'une page web statique, hors ligne et de se passer de la couche modèle du côté serveur. Cela offre la possibilité de synchroniser l'application avec un web service du côté serveur dès qu'il y a une connexion réseau.

IndexedDB est une base de données NoSQL et Objet, ce n'est donc pas une base de données relationnelle.

Dans ce tutoriel, nous allons créer une petite application qui stocke de simples notes avec leur date de création.

Nous allons voir comment stocker ces notes dans la base de données IndexedDB, comment les récupérer et les afficher. À la fin de ce tuto, nous verrons comment les trier par date.

Nous avons besoin de deux fichiers :

Créons notre base de données

Créons un fichier JavaScript nommé static_modele.js et ajoutons-y le code suivant :

      

// Déclaration des variables
let db;

// Création de 'maBaseDeDonnes'
let dbRequest = indexedDB.open('maBaseDeDonnees', 1);

dbRequest.onupgradeneeded = function (event) {
    // Affectation de la variable de la base de données
    db = event.target.result;
    // Créer un objet de type Store appelé notes
    // C’est dans cet objet que seront stockées les
    // notes dans la base de données.
    let notes = db.createObjectStore('notes', {
        autoIncrement: true
    });
}

dbRequest.onsuccess = function (event) {
    db = event.target.result;
}

dbRequest.onerror = function (event) {
    alert('Erreur à l’ouverture de la base de données : ' +
        event.target.errorCode);
}


      
    

Pour lancer ce code JavaScript, plaçons son appel dans le fichier index.html et ouvrons-le avec Firefox :

       
	
      
    

Avec l’outil de développement web de Firefox (CTRL + MAJ + i), on peut vérifier (dans l’onglet Stockage) que «maBaseDeDonnees» à bien été crée.

Saisie d’écran, de l’outil de développement web

Le code JavaScript

Retournons à notre code JavaScript et analysons-le ligne par ligne :

Les objets

L'objet IDBOpenDBRequest

À la ligne :

let dbRequest = indexedDB.open('maBaseDeDonnee', 1);

La variable dbRequest reçois un objet de type IDBOpenDBRequest qui donne un accès aux résultats des requêtes permettant d'ouvrir des bases de donnée.

Comment peut-on connaître le type de l'objet retourné par indexedDB.open() ?

Il suffi de d'afficher la propriété name de cette façon : dbRequest.constructor.name

Une des solutions c'est de l'afficher dans les log de cette façon :

console.log("Le nom de la classe de l'objet dbRequest : " + dbRequest.constructor.name);

Exercice :

Allez voir dans la d'oc de l'API ! et faites une recherche sur IDBOpenDBRequest, lisez la doc des événements :onupgradeneeded, onsuccess, onerror qui lui sont associés.

L'objet IDBDatabase

À ligne suivante :

db = event.target.result;

La variable db reçoit un objet de type IDBDatabase

Exercice :

Faire une recherche sur IDBDatabase dans la d'oc de l'API !

En résumé :

On peut utiliser un objet IDBDatabase pour ouvrir une transaction sur la base de données puis ajouter, éditer ou supprimer des enregistrements de cette base de données.

L'objet IDBObjectStore

La ligne suivante, va créer l’espace de stockage des notes dans la base de données :

let notes = db.createObjectStore('notes', {autoIncrement: true});

La variable notes reçoit un objet de type IDBObjectStore

Si on peut se permettre une comparaison inexacte, l'objet notes est un peu comme la référence à une table dans une base de données relationnelle.

L'objet notes, permet de :

des notes.

Exercice :

Faire une recherche sur IDBObjectStore dans la d'oc de l'API !

Voir ses propriétés et ses méthodes, surtout la méthode add(), dont nous allons bientôt avoir besoin

Les évènements

L'évènement onupgradeneeded

C'est dans la fonction appelée par ce évènement que l'on va définir les caractéristiques de la base de donnée.

En effet, cet évènement «écoute» les modifications, de la version de la base de donnée.

Ce numéro de version est passé en second paramètre à la méthode indexedDB.open('maBaseDeDonnes', 1)

Dans ce cas-ci c'est 1, étant la première version de la db.

Lorsqu'on la modifiera, par exemple, en lui ajoutant un index, il suffira de changer 1 à 2 pour que le code de la fonction appelée par l'évènement onupgradeneeded soit exécuté.

Par exemple, la ligne :

db.createObjectStore('notes', {autoIncrement : true});

Crée

  1. un index qui s'incrémente automatiquement à chaque ajout d'un objet dans la db;
  2. un objet de stockage (comme une table en SQL) de nom 'notes'

Nous reviendrons sur ce point à plusieurs reprises au cours de l'évolution du code de cette fonction

L'évènement onsuccess

Cet évènement appelle une fonction dans laquelle on récupère un objet de type IDBDatabase dont nous avons déjà parlé à la section : L'objet IDBDatabase.

db = event.target.result;

L'évènement onerror

En cas d'erreur de connexion, la fonction appelée par cet évènement l’envoie soit dans une alerte, soit dans les log, soit dans une.

Maintenant qu'on sait ce que contient la variable db, passons à une nouvelle étape !

Ajouter des notes dans la base de données

La fonction addNote()

    

function addNote(db, strnote) {
    // Démarre une transaction, dbTrans
    // reçoit un objet IDBTransaction
    let dbTrans = db.transaction([ 'notes' ], 'readwrite');
    // store reçoit un objet IDBObjectStore qui comporte
    // une méthode add()
    let store = dbTrans.objectStore('notes');
    let note = {
	text : strnote,
	timestamp : Date.now()
    };
    store.add(note);
    // Ferme la transaction
    dbTrans.oncomplete = function() {
	console.log('Note ajoutée !' + note)
    }
    dbTrans.onerror = function(event) {
	erreur = 'Erreur la note n’a pas été ajoutée ';
	console.log(erreur + event.target.errorCode);
    }
}      
    
  

La ligne suivante :

Démarre une transaction :

let dbTrans = db.transaction([ 'notes' ], 'readwrite');

dbTrans reçoit un objet IDBTransaction

La ligne suivante :

let store = dbTrans.objectStore('notes');

store reçoit un objet IDBObjectStore dont nous avons parlé à la section : L'objet IDBObjectStore.

Comme on l'a vu précédemment, cette ligne ajoute la note dans la db.

store.add(note);

L'évènement suivant :

dbTrans.oncomplete = function() { console.log('Note ajoutée !' + note) }

Ferme la transaction...

Toutes les modifications CRUD (Create, Read, Update, Delete), doivent se faire entre l’ouverture et une fermeture de transaction !

Bien sûr, on pourrait faire plusieurs opérations au cours d’une même transaction (avec une boucle par exemple).

Et notre note où est-elle ?

Avec l’outil de développement web de Firefox (CTRL + MAJ + i), on peut vérifier (dans l’onglet Stockage) que la note à bien été crée.

Saisie d’écran, de l’outil de développement web

Récupérer les notes de la base de données.

L'objet IDBRequest

Cet objet permet d’accéder au résultat des requêtes, en passant par ses événements.

Exemple récupérer une note par son id :

    

function uneNote(db) {
    let dbTrans = db.transaction([ 'notes' ], 'readonly');
    let store = dbTrans.objectStore('notes');
    // Retourne un objet IDBRequest
    let dbReq = store.get(1);
    dbReq.onsuccess = function(event) {
	// On ne récupère pas la note avec l’objet
	// dbReq, mais en passant parson évènement :
	let note = event.target.result;
	console.log(note.text + ' ' + new Date(
		note.timestamp).toString());
    }
}

    
	

C'est l'évènement qui permet de récupérer la note :

let note = event.target.result;

Ensuite on l’affiche dans les log :

console.log(note.text + ' ' + new Date( note.timestamp).toString());

Je n’ai pas fini ce tuto, mais si vous vous y intéressez, n’hésitez pas à me le faire savoir ! :-)