En este tema varemos diferentes APIs incluidas en HTML5 (como la de Local Storage) y otras que se han hecho muy populares como la de Google Maps.
HTML5 incluye un buen número de APIs que facilitan el trabajo con cosas complejas, como
Aquí comentaremos Storage, Drag&Drop, Geolocation, File Access, Communication, Web Workers, History y Offline
Con HTML5 es muy sencillo arrastrar y soltar elementos en una página web. Podemos arrastrar y soltar cualquier nodo DOM (una imagen, un archivo, enlaces, texto seleccionado, …). Para ello sólo es necesario que ese elemento tenga el atributo dragable="true"
. Si le ponemos false
no se podrá arrastrar y si no definimos el atributo podrá o no arrastrarse según el valor predeterminado del navegador (en la mayoría son dragables las imágenes, los links y las selecciones de texto).
Al arrastrar y soltar intervienen 2 elementos diferentes:
Para poder realizar la operación event tiene una propiedad llamada dataTransfer que es un objeto en el que almacenamos qué elemento estamos arrastrando (o cualquier otra cosa que queramos) y así cuando se suelte sobre el elemento destino éste último pueda saber quién se le ha soltado.
Los pasos para arrastrar y soltar un elemento son:
src
si es una imagen o su href
si es un enlace). Indicaremos el tipo del dato que estamos almacenando (texto plano, HTML, fichero, etc) y su valor. Ej.: <img id="imgGoogle" src="https://upload.wikimedia.org/wikipedia/commons/thumb/5/51/Google.png/320px-Google.png">
<div id="zonaDrop1" class="drop">
<p>Puedes soltar aquí la imagen</p>
</div>
<div id="zonaDrop2" class="drop">
<p>Y también aquí</p>
</div>
document.getElementById('imgGoogle').addEventListener('dragstart', (event) => {
event.dataTransfer.setData('text/plain', event.target.id); // Estamos guardando el texto 'imgGoogle'
})
document.getElementById('zonaDrop1').addEventListener('dragover', (event) => {
event.preventDefault();
})
document.getElementById('zonaDrop2').addEventListener('dragover', (event) => {
event.preventDefault();
})
document.getElementById('zonaDrop1').addEventListener('drop', (event) => {
event.preventDefault();
const data=event.dataTransfer.getData("text/plain"); // Obtenemos ìmgGoogle'
event.target.appendChild(document.getElementById(data));
})
document.getElementById('zonaDrop2').addEventListener('drop', (event) => {
event.preventDefault();
const data=event.dataTransfer.getData("text/plain"); // Obtenemos ìmgGoogle'
event.target.appendChild(document.getElementById(data));
})
Podéis ver el funcionamiento de este ejemplo:
NOTA: si hacemos draggable un elemento, por ejemplo un párrafo, ya no se puede seleccionar con el ratón ya que al pinchar y arrastrar se mueve, no se selecciona. Para poder seleccionarlo debemos pinchar y arrastrar el ratón con las teclas Ctrl+Alt pulsadas o hacerlo con el teclado. Ejemplo:
Podemos obtener más información de esta API MDN web docs.
EJERCICIO: mira y modifica el ejemplo de w3schools para entender bien el funcionamiento del Drag&Drop (ten en cuenta que en vez de
.addEventListener()
las llamadas a los escuchadores están puestas como atributos del HTML pero el funcionamiento es el mismo).
Antes de HTML5 la única manera que tenían los programadores de guardar algo en el navegador del cliente (como sus preferencias, su idioma predeterminado para nuestra web, etc) era utilizando cookies. Las cookies tienen muchas limitaciones y es engorroso trabajar con ellas.
HTML5 incorpora la API de Storage para subsanar esto. Además existen otros métodos de almacenamiento en el cliente más avanzados como IndexedDB (es un estándar del W3C pero aún con poco soporte entre los navegadores).
El funcionamiento de la API Storage es muy sencillo: dentro del objeto window tendremos los objetos localStorage y sessionStorage donde podremos almacenar información en el espacio de almacenamiento local (5 o 10 MB por sitio web según el navegador, que es mucho más de lo que teníamos con las cookies). La principal diferencia entre ellos es que la información almacenada en localStorage nunca expira, permanece allí hasta que la borremos (nosotros o el usuario) mientras que la almacenada en sessionStorage se elimina automáticamente al cerrar la sesión el usuario.
Sólo los navegadores muy antiguos (Internet Explorer 7 y anteriores) no soportan esta característica. Puedo saber si el navegador soporta o no esta API simplemente mirando su typeof
:
if (typeof(Storage) === 'undefined') // NO está soportado
Tanto localStorage como sessionStorage son como un objeto global al que tengo acceso desde el código. Lo que puedo hacer con ellos es:
localStorage.setItem('dato', 'valor')
o también localStorage.dato = 'valor'
let miDato=localStorage.getItem('dato')
o también let miDato = localStorage.dato
localStorage.removeItem('dato')
para borrar ‘dato’. Si quiero borrar TODO lo que tengo localStorage.clear()
localStorage.length
Sólo podemos guardar objetos primitivos (cadenas, números, …) por lo que si queremos guardar un objeto o un array hay que convertirlo a una cadena JSON con localStorage.setItem('dato', JSON.stringify('objeto'))
. Para recuperar el objeto haremos let miObjeto = JSON.parse(localStorage.getItem('dato'))
.
Cada vez que cambia la información que tenemos en nuestro localStorage se produce un evento storage. Si, por ejemplo, queremos que una ventana actualice su información si otra cambia algún dato del storage haremos:
window.addEventListener("storage", actualizaDatos);
y la función ‘actualizaDatos’ podrá leer de nuevo lo que hay y actuar en consecuencia.
EJERCICIO: comprueba qué tienes almacenado en el localStorage y el sessionStorage de tu navegador. Guarda y recupera algunas variables. Luego cierra el navegador y vuelve a abrir la página. ¿Están las variables guardadas en localStorage? ¿Y las de sessionStorage?
Puedes ver un ejemplo en este vídeo de cómo almacenar en el Storage datos del usuario.
localStorage, sessionStorage y cookies almacenan información en un navegador específico del cliente, y por tanto:
Podríamos usar localStorage para almacenar localmente los datos con los que trabaja una aplicación web. Así conseguiríamos minimizan los accesos al servidor y que la velocidad de la aplicación sea mucho mayor al trabajar con datos locales. Pero periódicamente debemos sincronizar la información con el servidor.
Ventajas de localStorage:
Ventajas de las cookies:
Son pequeños ficheros de texto y tienen las siguientes limitaciones:
Cada cookie almacena los siguientes datos:
Un ejemplo de cookie sería:
username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 UTC;
Se puede acceder a las cookies desde document.cookie que es una cadena con las cookies de nuestras páginas. Para trabajar con ellas conviene que creemos funciones para guardar, leer o borrar cookies, por ejemplo:
function setCookie(cname, cvalue, cexpires, cpath, cdomain, csecure) {
document.cookie = cname + '=' + cvalue +
(cexpires?';expires='+cexpires.toUTCString():'') +
(cpath?';path='+cpath:'') +
(cdomain?';domain='+cdomain:'') +
(csecure?';secure':'')
}
function getCookie(cname) {
if (document.cookie.length > 0) {
let start = document.cookie.indexOf(cname + '=');
if (start !== -1) { // Existe la cookie
start = start + cname.length + 1; // Inicio del valor
let end = document.cookie.indexOf(';', start);
if (end === -1) { // Si no encuentra ';', es la última cookie
end = document.cookie.length;
}
return document.cookie.substring(start, end); // Extrae el valor
}
}
return ''; // No se encontró la cookie
}
function delCookie(cname) {
return document.cookie = cname + '=;expires=Thu, 01 Jan 1970 00:00:01 GMT;'
}
Podéis ver en este vídeo un ejemplo de cómo trabajar con cookies, aunque como ya hemos dicho lo recomendable es trabajar con Storage.
Esta API permite a la aplicación web acceder a la localización del usuario si éste da su permiso. Muchos navegadores sólo permiten usarlo en páginas seguras (https).
Podemos acceder a esta API mediante el objeto geolocation de navigator. Para saber si nuestro navegador soporta o no la API podemos hacer:
if (geolocation in navigator) // devuelve true si está soportado
Para obtener la posición este objeto proporciona el método navigator.geolocation.getCurrentPosition() que hace una petición asíncrona. Cuando se reciba la posición se ejecutará la función callback que pasemos como parámetro y que recibirá las coordenadas de la localización. Podemos pasar otra como segundo parámetro que se ejecutará si se produce algú error y que recibirá un objeto con la propiedad code que indica el error producido. Ej.:
navigator.geolocation.getCurrentPosition(
(position) => {
pinta_posicion(position.coords.latitude, position.coords.longitude)
},
(error) => {
switch(error.code) {
case error.PERMISSION_DENIED: // El usuario no autoriza al navegador a acceder a la localización
msg = 'El usuario ha denegado la petición de geolocalización'
break
case error.POSITION_UNAVAILABLE: // No se puede obtener la localización
msg = 'La información de localización no está disponible.'
break
case error.TIMEOUT: // Ha expirado el tiempo para obtener la localización
msg = 'Ha expirado el tiempo para obtener la localización'
break
case error.UNKNOWN_ERROR:
msg = 'Se ha producido un error desconocido.'
break
}
muestra_error(msg)
}
)
Si queremos ir obteniendo continuamente la posición podemos usar el método .watchPosition() que tiene los mismos parámetros y funciona igual pero se ejecuta repetidamente. Este método devuelve un identificador para que lo podemos detener cuando queremos con .clearWatch(ident). Ej.:
const watchIdent = navigator.geolocation.watchPosition(
(position) => pinta_posicion(position.coords.latitude, position.coords.longitude),
(error) => muestra_error(error)
)
...
// Cuando queremos dejar de obtener la posición haremos
navigator.geolocation.clearWatch(watchIdent)
Las principales propiedades del objeto de localización (algunas sólo estarán disponible cuando usemos un GPS) son:
Podemos pasarle como tercer parámetro al método getCurrentPosition un objeto JSON con una o más de estas propiedades:
Podemos obtener más información de esta API en MDN web docs y ver y modificar ejemplos en w3schools y muchas otras páginas. i
Para poder utilizar la API en primer lugar debemos obtener una API KEY de Google.
Una vez hecho para incluir un mapa en nuestra web debemos cargar la librería para lo que incluiremos en nuestro código el script:
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=ESCRIBE_AQUI_TU_API_KEY&callback=initMap">
</script>
(el parámetro callback será el encargado de llamar a la función initMap() que inicie el mapa)
Ahora incluir un mapa es tán sencillo como crear un nuevo objeto de tipo Map que recibe el elemento DOM donde se pintará (un div normalmente) y un objeto con los parámetros del mapa (como mínimo su centro y el zoom):
let map
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: { lat: 38.6909085, lng: -0.4963000000000193 },
zoom: 12
})
}
Por su parte añadir un marcador es igual de simple. Creamos una instancia de la clase Marker a la que le pasamos al menos la posición, el mapa en que se creará y un título para el marcador:
let marker = new google.maps.Marker({
position: { lat: 38.6909085, lng: -0.4963000000000193 },
map: map,
title: 'CIP FP Batoi'
})
Aquí tenéis el ejemplo anterior:
Podemos obtener más información de esta API en Google Maps Plataform, en el tutorial de w3schools y en muchas otras páginas.