El almacenamiento de datos en el navegador usando JavaScript, además de las cookies, ya es una cosa que salió hace mucho tiempo. Sin embargo, muchas personas todavía no conocen sobre el tema o saben poco sobre el mismo.
Es por eso que en este post voy a explicar cómo trabajar con la API de localStorage en JavaScript para almacenar datos en el navegador del usuario, pero lo más importante es que estos datos van a persistir aunque el navegador se cierre o se actualice.
Nota: si quieres ver un ejemplo de localStorage mira este generador de UML.
Soporte de localStorage en los navegadores
Al momento de escribir este post, cualquier navegador decente soporta la tecnología localStorage en JavaScript, aunque para estar seguros veremos una forma de comprobar si el navegador lo soporta.
Recomendado: pouchDB
Hace mucho tiempo utilicé PouchDB para un proyecto que hice; pues esa librería de JavaScript es parecida a esto que veremos (aunque PouchDB es mejor y más robusta) ya que permite guardar datos de forma local.
Si quieres ver un ejemplo de PouchDB mira este ejemplo que hice.
Lecturas recomendadas
En los ejemplos uso funciones flecha y declaro algunas variables con let
, mira los posts si quieres:
Let, const y var en JavaScript
Detectar soporte de localStorage
Bueno, comencemos por ver si el navegador soporta localStorage. Como lo dije, cualquier navegador decente debe soportar esto. Mira la página de Can I Use para más información sobre el soporte.
No te preocupes por el código, más abajo lo vas a entender.
const funcionaLocalStorage = () => {
// Si no existe el objeto, pues no hay soporte
if(!window.localStorage) return false;
// Ahora intentamos insertar y eliminar
try{
let id = "un_id_que_no_debe_repetirse";
localStorage.setItem(id, "Soy un valor");
localStorage.removeItem(id);
return true;
}catch(e){
// Está lleno, está en modo privado, o cualquier cosa
console.log(e);
return false;
}
};
Lo que estamos haciendo primero es ver si existe el objeto localStorage
; pero que exista no significa que funcione, así que aparte de ello intentamos alojar y luego eliminar un elemento; si no se genera una excepción entonces significa que localStorage funciona como un encanto.
Cuidado con los tipos de datos
localStorage va a almacenar los datos como cadena, llamando al método toString
del objeto que le pasemos. Por ello es que no debemos confiar en que va a respetar los tipos de dato; es decir, si le pasamos un entero, al recuperarlo lo tendremos como cadena.
Lo peor de esto es que si almacenamos un objeto, va a devolver la cadena literal [object Object]
en lugar del objeto, hay que tener cuidado.
Más información sobre los lenguajes fuertemente y débilmente tipados aquí.
Entonces, ¿cómo almaceno más que cadenas con localStorage?
Qué malo eres, localStorage, ¿cómo es que no soportas más que cadenas? bueno, antes de comenzar a reclamar hay que recordar la existencia de JSON y la serialización de datos.
Ya que localStorage
almacena cadenas, pues hay que pasarle un JSON en caso de que vayamos a guardar un objeto complejo. Si queremos números, siempre podemos cambiarlos de dato con parseInt
o parseFloat
En resumen, si quieres almacenar objetos (cosa que es totalmente posible y común) codifícalos con JSON, y al recuperarlos decodifícalos.
No te voy a enseñar cómo trabajar con JSON porque ya he escrito un post sobre eso, el cual te recomiendo leer, pero en resumen usa JSON.stringify
y JSON.parse
.
Insertar elemento
Para insertar o añadir un elemento con localStorage existen dos maneras. La primera es declarar una propiedad del objeto localStorage y la segunda es llamar a setItem
.
Vamos a centrarnos en la segunda, pues es más explícita. La sintaxis es:
localStorage.setItem("Clave", "Valor");
Así de simple es. Abajo muestro un ejemplo con varios tipos de datos, incluyendo a JSON.
localStorage.setItem("nombre", "Luis Cabrera Benito");
localStorage.setItem("edad", 123);
localStorage.setItem("recibirNotificaciones", true);
// Un objeto complejo
const mascota = {
nombre: "Maggie",
edad: 2,
amigos: ["Meca", "Guayaba", "Snowball"]
};
localStorage.setItem("mascota", JSON.stringify(mascota));
¿Qué pasa si la clave ya existe?
No pasa nada, se actualiza el objeto.
Actualizar datos
Para actualizar los datos en localStorage, hay que llamar a setItem
de nuevo y pasarle el dato completo que se va a almacenar.
Esto no funciona como los update de SQL en donde solamente actualizamos lo necesario, aquí tienes que pasar el dato completo y actualizado.
Saber si ya existe
Para saber si un valor ya existe con determinada clave, podemos usar hasOwnProperty
o un simple if accediendo al valor.
if(localStorage.hasOwnProperty("edad")){
// Perfecto, ya había un elemento con el id edad
}
// Otra forma:
if(localStorage.edad){
// Ok, hay edad
}
// Todavía otra forma
if(localStorage["edad"]){
// Ok hay edad :)
}
Cabe mencionar que es más recomendable usar hasOwnProperty
, ya que JavaScript evalúa las cadenas vacías y el número 0 como false
.
Eliminar datos
Para eliminar un dato de localStorage utiliza removeItem()
y pásale la clave. La sintaxis es:
localStorage.removeItem("clave");
Obtener un valor
Si quieres recuperar un valor que guardaste anteriormente, llama a getItem
pasándole la clave. Así:
let valorGuardado = localStorage.getItem("clave");
Recuerda que lo va a devolver como cadena y que debes convertirlo a determinado tipo si lo quieres usar. En el siguiente ejemplo muestro cómo recuperar y castear los objetos:
// Recuperar elementos
// No parsear porque lo queremos como cadena
let nombre = localStorage.getItem("nombre");
console.log("Te llamas ", nombre);
// convertir a entero
let edad = parseInt(localStorage.getItem("edad"));
console.log("Tu edad es: ", edad);
// Convertir a booleano
let recibirNotificaciones = Boolean(localStorage.getItem("recibirNotificaciones"));
console.log("¿Quiere recibir notificaciones?", recibirNotificaciones);
// Y a objeto
let mascotaDecodificada = JSON.parse(localStorage.getItem("mascota"));
console.log("La mascota es: ", mascotaDecodificada);
En el ejemplo estamos convirtiendo las cadenas a sus valores “reales” con todo y tipo de dato. Al imprimir los datos, se imprimen como son, no como cadenas:
Otra forma de obtener los valores
Ah, por cierto, para obtener un valor también podemos obtener la propiedad de localStorage
. Por ejemplo, para obtener la edad usamos:
let edad = localStorage.edad;
En este caso no lo hacemos así porque no seríamos explícitos; desaconsejo usar esa manera.
Obtener todos los datos
Para obtener todos los registros que hemos guardado, sin saber la clave de los mismos, simplemente debemos acceder a todas las claves de localStorage
.
Eso se logra gracias al fabuloso método llamado Object.keys recientemente introducido (no tiene nada que ver con localStorage
, son cosas distintas) el cual devuelve un arreglo que tiene todas las claves, más tarde podemos iterarlo e ir obteniendo ese valor.
Veamos el ejemplo:
// Obtener todas las claves almacenadas
let claves = Object.keys(localStorage);
// Y por cada clave, ir obteniendo el valor de localStorage
claves.forEach(clave => {
console.log("Tengo una clave: ", clave);
let valor = localStorage.getItem(clave);
// Castearlo o convertirlo depende de ti
console.log("En esa clave el valor es:", valor);
});
Usamos un forEach
que podría ser remplazado por un ciclo for normal. Lo importante es que usamos getItem
para obtener el valor, y gracias a ello podemos obtener todos los elementos guardados.
Conclusión
En este ejemplo guardamos valores nativos y simples, pero pensándolo bien y creando una bonita estructura podemos crear grandiosas cosas y sistemas complejos; eso sí, recuerda que estos datos se quedan en el navegador y que aunque el límite es grande, existe.
Por otro lado, si el usuario desinstala el navegador u obliga a que se borren los datos, nada podrás hacer. Justamente por eso es que se prefiere el uso de la arquitectura cliente-servidor.
Pingback: Generador de diagramas de clase UML con JavaScript - Parzibyte's blog