Transparencias javascript APIs

Anuncio
Tema 2. Programación en el cliente con Javascript
2.3 Manejo del DOM
El DOM
• Como ya hemos visto, por cada etiqueta HTML existe un objeto
Javascript equivalente
• Es decir, el navegador mantiene en memoria un modelo orientado
a objetos del documento que refleja la estructura del HTML
• El DOM es un árbol. Cada “componente” del HTML es un nodo
• Los cambios en el DOM se reflejan en “tiempo real” en el HTML
<!DOCTYPE html>
<html>
<head>
<title>Ejemplo de DOM</title>
</head>
<body>
<!-- es un ejemplo un poco simple -->
<p style=“color:red”>Bienvenidos al <b>DOM</b></p>
</body>
</html>
Aplicaciones Distribuídas en Internet 2015-16 / U. Alicante
API DOM estándar (Level 1)
• Se manipulan los nodos del árbol, lo que a su vez “modifica” el
HTML
• Muy potente, pero también algo tedioso de utilizar
<input type="button" value="Añadir párrafo" id="boton"/>
<div id="texto"></div>
<script type="text/javascript">
document.getElementById("boton").onclick = function() {
var texto = prompt("Introduce un texto para convertirlo en párrafo");
/* Nótese que la etiqueta <p> es un nodo, y el texto que contiene es OTRO
nodo, de tipo textNode, hijo del nodo <p> */
var p = document.createElement("P");
var nodoTexto = document.createTextNode(texto);
p.appendChild(nodoTexto);
document.body.appendChild(p);
};
</script>
http://jsbin.com/Uwoduf/1/watch?html,js,output
Aplicaciones Distribuídas en Internet 2015-16 / U. Alicante
Manipular directamente HTML
• innerHTML: propiedad que nos permite leer/modificar el código
HTML que hay dentro de una etiqueta
• No es estándar en HTML4, pero sí en HTML5
• No se puede (debe) usar para editar tablas. Para eso existen
métodos alternativos (ver p.ej. http://msdn.microsoft.com/en-us/
library/ms532998(v=vs.85).aspx)
<input type="button" value="Pon texto" onclick="ponTexto()"/>
<div id="texto"></div>
<script type="text/javascript">
function ponTexto() {
var mensaje = prompt("Dame un texto y lo haré un párrafo")
var miDiv = document.getElementById("texto")
miDiv.innerHTML += "<p>" + mensaje + "</p>"
}
</script>
Aplicaciones Distribuídas en Internet 2015-16 / U. Alicante
Modificar el HTML
• insertAdjacentHTML: método para poder insertar HTML antes/
en medio/después de una etiqueta HTML
• insertAdjacentHTML(posicion, texto)
• posicion: “beforebegin”, “afterbegin”, “beforeend”, “afterend”
• texto: se evaluará y convertirá a HTML
<div id="texto">Hola </div>
<button id="boton">Añadir</button>
<script>
document.getElementById("boton").onclick = function() {
var texto = document.getElementById("texto");
texto.insertAdjacentHTML("beforeend", "<b>mundo</b>");
texto.insertAdjacentHTML("afterend", "<div>más texto</div>");
}
</script>
http://jsbin.com/dovoxecipu
Aplicaciones Distribuídas en Internet 2015-16 / U. Alicante
Seleccionar nodos
• Por id
var noticias = document.getElementById("noticias")
• Por etiqueta
//Reducir el tamaño de todas las imágenes a la mitad
var imags = document.getElementsByTagName("img");
for(var i=0; i<imags.length; i++) {
imags[i].width /= 2;
imags[i].height /= 2;
}
• Usando selectores CSS
//Obtener el 1er nodo que cumple la condición
var primero = document.querySelector(".destacado");
//Obtenerlos todos
var nodos = document.querySelectorAll(".destacado");
//Cambiamos la clase. Nótese que es “className”, no “class”
for (var i=0; i<nodos.length; i++) {
nodos[i].className = "normal";
}
//selectores un poco más complicados
var camposTexto = document.querySelectorAll('input[type="text"]');
var filasPares = document. querySelectorAll("tr:nth-child(2n)")
Aplicaciones Distribuídas en Internet 2015-16 / U. Alicante
jQuery
• El framework que popularizó la idea de usar selectores CSS para
seleccionar nodos del DOM
$(‘img.icono’)
.hide(3000)
.addClass(‘oculto’)
• Además de esto jQuery tiene muchas otras funcionalidades, y sobre
todo proporciona una capa de compatibilidad con navegadores no
estándar
Aplicaciones Distribuídas en Internet 2015-16 / U. Alicante
Tema 2. Programación en el cliente con Javascript
2.4 AJAX
AJAX
• Asynchronous Javascript And XML
• Combinación de tecnologías:
• XMLHttpRequest: hacer peticiones al servidor con Javascript y recibir la
respuesta sin recargar la página ni cambiar de página
• Formatos JSON/XML: recibir información estructurada en la respuesta
• API DOM: actualizar solo parte de la página con datos procedentes del servidor
• Se convirtió en una de las características distintivas de las
aplicaciones “web 2.0”
Aplicaciones Distribuídas en Internet 2015-16 / U. Alicante
Código asíncrono
• Javascript usa un único hilo, si la ejecución se bloqueara hasta que
respondiera el servidor, mientras tanto no podríamos hacer nada más
var req = new XMLHttpRequest();
//preparar la petición. El tercer parámetro indica que es asíncrona req.open('GET', 'http://www.miservidor.com/miprograma.php?cod='+codigo, true);
//decir qué función hace de “callback”. Esto no se debe hacer antes del open
req.onreadystatechange = mi_callback;
req.send();
console.log('Esto se ejecutará inmediatamente después del send()');
//Ejemplo de petición POST var req = new XMLHttpRequest();
req.open('POST', 'http://www.miservidor.com/miprograma.php', true);
req.onreadystatechange = mi_callback;
//Si enviamos parámetros HTTP esto es necesario. Si enviamos JSON no.
req.setRequestHeader(“Content-type","application/x-www-form-urlencoded")
//Los datos se envían en el send
req.send('cod='+codigo);
Aplicaciones Distribuídas en Internet 2015-16 / U. Alicante
El callback
• Para informar del progreso puede llamarse varias veces con distintos
valores de la propiedad readyState (valores entre 2 y 4). Normalmente
nos interesa el 4, hasta entonces la respuesta no se ha recibido entera
function mi_callback() {
if ((this.readyState == 4) && (this.status == 200)) console.log(this.responseText); }
//callback definido “sobre la marcha”, como una función anónima
xhr.onreadystate = function() {
//podemos usar la clausura generada para referenciar variables “externas”
if ((xhr.readyState == 4) && (xhr.status == 200)) console.log(xhr.responseText); }
Aplicaciones Distribuídas en Internet 2015-16 / U. Alicante
¿Pero dónde está XML?
• En el AJAX original, la información se enviaría en XML, que
permite estructurar los datos de manera más “elegante” que un
formato “casero” ad-hoc
<chat>
<mensaje>
<hora>10:00:05</hora>
<login>Pepito</login>
<texto>Hola a todos…</texto>
</mensaje>
…
</chat>
• Problema: aunque el API DOM de Javascript permite parsear XML,
resulta tedioso de usar
Aplicaciones Distribuídas en Internet 2015-16 / U. Alicante
JSON y AJAX
• JSON es mucho más fácil de tratar que XML, gracias a
JSON.parse o a eval
[
{"hora":"10:00:05", "login":"pepito", "texto":"hola a todos…"},
{"hora":"10:00:15", "login":"jorgito", "texto":"hola pepito, cuánto
tiempo sin saber de ti! :)"}
]
mensajes = JSON.parse(req.responseText)
for(i=0; i<mensajes.length; i++) {
console.log("A las " + mensajes[i].hora + " " + mensajes[i].login +
" dijo: " + mensajes[i].texto);
}
Aplicaciones Distribuídas en Internet 2015-16 / U. Alicante
Peticiones REST con JS
• Firmar una petición en un API tipo change.org
xhr.open('POST', 'api/peticiones/' + idPeticion + "/firmas" , true)
xhr.onreadystatechange = function() {
...
}
xhr.setRequestHeader("Content-type", "application/json")
var firma = {};
firma.email = document.getElementById("email").value;
firma.comentario = document.getElementById("comentario").value
...
firma.publica = document.getElementById(“publica").checked;
xhr.send(JSON.stringify(firma))
Aplicaciones Distribuídas en Internet 2014-15 / U. Alicante
AJAX “nivel 2”
• “Versión 2.0” de XMLHttpRequest que permite
• Intercambiar datos binarios con el servidor. Por ejemplo, esto puede servir para
subir imágenes o archivos en general
• Acceder a ciertos eventos, por ejemplo para ir monitorizando el progreso en el
envío/recepción de datos
• Solo en navegadores modernos (>=IE10)
• API
• FormData representa los campos de un formulario, incluyendo type=”file”.
Enviando el FormData enviamos también el archivo
• Hay varios eventos como “progress”, “load”,”error” o “abort”
• La gestión de los eventos se hace con el estándar W3C de event listeners, sobre el
objeto XMLHttpRequest
Aplicaciones Distribuídas en Internet 2015-16 / U. Alicante
Ejemplo de AJAX Level 2
<script>
function verProgreso(e) {
var progreso= document.getElementById("progreso");
progreso.innerHTML = Math.round((e.loaded / e.total)*100)+"%";
}
function uploadAJAX() {
var fdata = new FormData(document.getElementById("formu"))
var xhr = new XMLHttpRequest();
xhr.addEventListener("progress", verProgreso)
xhr.addEventListener("load", function() {
alert(this.responseText)
});
xhr.addEventListener("error", function() {
alert("error: " + this.status);
});
xhr.open("POST", "http://loquesea.com/imagenes", true)
xhr.setRequestHeader("Content-type", "multipart/form-data")
xhr.send(fdata)
}
</script>
<form id="formu">
Elegir archivo: <input type="file" name="archivo"/> <br/>
<input type="button" value="enviar" onclick="uploadAJAX()"/>
</form>
<div id="progreso"></div>
Aplicaciones Distribuídas en Internet 2015-16 / U. Alicante
Fetch API
• Sustituto moderno de XMLHttpRequest
• Usa promesas en lugar de callbacks
• En “proceso de implantación”
fetch('./api/some.json')
.then(
function(response) {
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' +
response.status);
return;
}
// Examine the text in the response
response.json().then(function(data) {
console.log(data);
});
}
)
.catch(function(err) {
console.log('Fetch Error :-S', err);
})
Aplicaciones Distribuídas en Internet 2015-16 / U. Alicante
Restricciones de seguridad
• Política de seguridad del “mismo origen”: un XMLHttpRequest
solo puede hacer una petición AJAX al mismo host del que vino la
página en la que está definido
• Por ejemplo, el Javascript de una página de www.vuestrositio.com en principio no
puede hacer peticiones AJAX a Facebook
• En realidad la petición se hará, pero el navegador no nos dará acceso al resultado
Aplicaciones Distribuídas en Internet 2015-16 / U. Alicante
Cross-Domain AJAX
• Estándar CORS (Cross Origin Resource Sharing): permite saltarse la
same origin policy con la colaboración del servidor
• En cada petición cross-domain el navegador envía una cabecera Origin con el
origen de la petición. Es imposible falsearla desde JS
• El servidor puede enviar una cabecera Access-Control-Allow-Origin
indicando los orígenes desde los que se puede acceder a la respuesta. Si encajan
con el origen del XMLHttpRequest el navegador dará “luz verde”
HTTP/1.1 200 OK Server: Apache/2.0.61 Access-Control-Allow-Origin: * Aplicaciones Distribuídas en Internet 2015-16 / U. Alicante
El tag <script> y la seguridad
• Las restricciones de seguridad no se aplican a la etiqueta <script>.
Con ella podemos cargar (¡¡y ejecutar!!) código Javascript de
cualquier origen
• En lugar de cargar un script podríamos cargar en un punto del
documento la respuesta del servidor en JSON a una llamada a un
API, por ejemplo. Solo nos falta disparar un JS para poder procesar
estos datos
<script
src=“https://api.flickr.com/services/rest?
format=json&method=flickr.photos.search&tags=gatitos&api_key=8bd6
dfb55bc750946f80606ef5aefaca”>
</script>
Aplicaciones Distribuídas en Internet 2014-15 / U. Alicante
JSONP
• Si consiguiéramos ejecutar una función nuestra que recibiera como
parámetro el JSON que envía el servidor todo estaría resuelto
• En los servicios que admiten JSONP, debemos pasar un parámetro
(normalmente se llama “callback” o algo similar) con el nombre de la
función a llamar
http://api.flickr.com/services/rest?
format=json&method=flickr.photos.search&api_key=<TU_API_KE
Y>&tags=gatitos&jsoncallback=miFuncion
• El servidor devolverá un resultado del estilo
miFuncion(JSON_RESULTADO_DE_LA_PETICION)
Aplicaciones Distribuídas en Internet 2014-15 / U. Alicante
Ejecutando JSONP “a petición”
• Una etiqueta <script> creada dinámicamente se ejecuta en el
momento en que se inserta en el documento
<script>
document.getElementById(“buscar").onclick = hacerBusqueda() {
var tags = document.getElementById("tags").value
miScript = document.createElement("script")
miScript.src = "https://api.flickr.com/services/rest?
format=json&method=flickr.photos.search&api_key=8bd6dfb55bc750946f80606
ef5aefaca&jsoncallback=miCallback&tags=" + tags
document.body.appendChild(miScript)
}
function miCallback(json){alert(JSON.stringify(json))}
</script>
<input type=“text” id=“tags”>
<button id=“buscar”>Buscar</button>
http://jsbin.com/doniqorete
Aplicaciones Distribuídas en Internet 2014-15 / U. Alicante
Tema 2. Programación en el cliente con Javascript
2.5 Local Storage
Local Storage API
• Permite compartir variables entre páginas
• Características:
• Se almacenan pares “clave=valor”
• Aunque la especificación no restringe el tipo para el valor, por el momento todos los
navegadores lo almacenan como String
• Esto quiere decir que al recuperarlo tendremos que convertirlo al tipo original.
• Un enfoque muy típico es usar JSON, así podemos guardar objetos
• Convertir de objeto a cadena: JSON.stringify(objeto)
• de cadena a objeto: JSON.parse(cadena)
• Hay dos tipos de almacenamiento
• Objeto localStorage: el ámbito del dato es el sitio web. Se conserva aunque se
cierre el navegador
• Objeto sessionStorage: el ámbito es la ventana (o solapa, si tenemos varias
abiertas). Se conserva hasta que ésta se cierre
Aplicaciones Distribuídas en Internet 2015-16 / U. Alicante
API básico de Local Storage
• getItem(clave)
• setItem(clave,valor)
• length: propiedad de solo lectura que indica cuántos pares clave/
valor hay almacenados
• key(i): devuelve el nombre de la clave i-ésima (para poder
recuperar su valor con getItem)
• clear(): eliminar todos los datos
Aplicaciones Distribuídas en Internet 2015-16 / U. Alicante
Ejemplo
function guardarNombre() {
nombre = prompt("¿cómo te llamas?")
localStorage.setItem("usuario", nombre)
//esta sintaxis es equivalente a lo anterior
localStorage.usuario = nombre
//y esta también
localStorage["usuario"] = nombre
edad = prompt("¿Cuántos años tienes?")
localStorage.setItem("edad", edad)
}
function mostrarNombre() {
alert("Me acuerdo de ti, " + localStorage.usuario +
" vas a cumplir " + parseInt(localStorage.edad) + 1 !! +"años")
}
function mostrarTodosLosDatos() {
datos=""
for(var i=0; i<localStorage.length; i++) {
clave = localStorage.key(i)
datos = datos + clave + "=" + localStorage[clave] + '\n'
}
alert("LocalStorage contiene " + datos)
}
Aplicaciones Distribuídas en Internet 2015-16 / U. Alicante
Descargar