Professional Documents
Culture Documents
Ingeniera de Sistemas de
Informacin!
Grado en Ingeniera en Tecnologas de
Telecomunicacin!
GSyC!
GSyC!
2!
Contenidos!
Introduccin!
El Document Object Model (DOM)!
Registro de manejadores de eventos sobre
elementos del DOM!
AJAX!
Otros usos de JavaScript!
Precauciones!
GSyC!
3!
Para depurar: !
console.log("hola mundo")
alert("hola")
Depurador de firebug!
Extensin de Firefox tilt para ver DOM en 3D: disponible en las ltimas
versiones de Firefox en el men Tools->Web Developer!
Y para trastear con JavaScript + HTML + CSS:!
http://jsfiddle.net!
GSyC!
4!
Introduccin!
Usos de JavaScript!
1. Client-side JavaScript: !
2.
3.
GSyC!
6!
Client-side JavaScript!
En este tema no se abordan las aplicaciones tipo desktop
programadas en JavaScript ni JavaScript en el servidor ni JavaScript
en los mviles!
Aprenderemos cmo usar JavaScript en el browser para mejorar la
interactividad con la interfaz!
Aprenderemos cmo usar jQuery como framework para consultar y
modificar los elementos del documento HTML cargado en el browser!
Aprenderemos a usar AJAX para que el cdigo JavaScript cargado en
una pgina realice RPCs a las acciones de controladores Rails !
Las acciones Rails devolvern vistas parciales que el cdigo JavaScript que corre
en el browser usar para modificar el documento HTML desde el que se hizo la
RPC!
!
7!
La posicin privilegiada de
JavaScript!
JavaScript es un lenguaje ms!
Pero al correr en el browser el cdigo
JavaScript puede:!
1. Ser ejecutado como consecuencia de la interaccin del
usuario con la interfaz grfica de la pgina: click de
ratn, ratn pasando por encima, pulsar tecla,!
2. Realizar peticiones HTTP al servidor sin necesidad de
tener que recargar toda una pgina!
3. Ser ejecutado cuando el servidor enve una respuesta
HTTP a una peticin !
4. Consultar y modificar el documento cargado,
redibujndolo si hay cambios!
GSyC!
8!
GSyC!
9!
'fichero_javascript'
En Rails:!
1. El cdigo JavaScript que escribamos para nuestra aplicacin se pone en ficheros con
extensin .js en el directorio app/assets/javascripts
2. El helper de Rails javascript_include_tag 'application' puede incluirse en cualquier template, p.ej.
en app/views/layouts/application.html.haml
Este fichero JavaScript produce el efecto de que al desplegar en produccin la aplicacin, Rails concatenar y
comprimir (minifying) todos los .js del directorio app/assets/javascripts junto a la biblioteca jQuery, y pondr
un fichero nico para toda la aplicacin en el dir public
GSyC!
10!
DOM!
DOM: Document Object Model!
World Wide Web Consortium Document Object Model: !
"a platform and language-neutral interface that will allow
programs and scripts to dynamically access and update the
content, structure and style of documents"!
12!
DOM!
Inspeccin del DOM en
Firefox: !
Arrancando firebug, o!
Men Herramientas->
Desarrollador Web ->
Inspeccionar, !
y abajo a la derecha,
Vista 3D!
Si no lo ves, instala un
Firefox ms reciente, o
instala la extensin tilt!
GSyC!
13!
14!
JSAPI!
El objeto window ofrece algo ms que el DOM!
Ofrece propiedades y funciones para manipular el DOM y otras
especficas del browser, con el nombre de API JSAPI!
location, document, document.head, document.body,
document.write(string), alert(string), confirm
(string),
Ejemplo: prueba a asignar una url a window.location en la consola!
GSyC!
15!
jQuery!
jQuery es una API que recubre JSAPI,
proporcionando uniformidad entre browsers!
Usaremos jQuery y no JSAPI!
GSyC!
16!
17!
qu selecciona !
h1
div#message
.red
div.red, h1
div#message h1
a.lnk
a.lnk:hover
cualquier elemento h1
*el* elemento div cuyo ID es message
cualquier elemento de clase red
los elementos div de clase red o cualquier h1
los elementos h1 dentro de los div de clase message
elementos de clase lnk
elementos a con clase lnk, cuando se pasa por
encima de ellos (hover)
http://www.w3.org/TR/selectors/#selectors!
jQuery('#movies')
$('#movies')
$('h1.title')
GSyC!
18!
Propiedades y funciones de
elementos DOM recubiertos
por jQuery()/$()!
Hay 3 tipos de acciones que se pueden realizar sobre
un elemento o un conjunto de elementos devueltos por
jQuery('selector-CSS')/$('selector-CSS'):!
1. Cambiar su aspecto visual modificando la clase CSS del/de
los elementos!
2. Cambiar su contenido modificando el html del/de los
elementos o el texto plano del elemento!
3. Animar el/los elementos (mostrar/ocultar, desvanecerse/
reaparecer, )!
Consulta http://api.jquery.com/ !
A continuacin presentamos algunas funciones!
GSyC!
19!
.is(:cond')
':disabled'
.val([val])
GSyC!
20!
al elemento
Animaciones:
.hide([duracion][,callback]), .show([duracion][,callback])
Muestra/oculta el elemento, tardando duracion ('fast', 'slow' o
milisegundos), y cuando termina llama a callback
.slideUp([duracion][,callback]), Desaparece
.slideDown([duracion][,callback]),
.slideToggle([duracion][,callback])
.fadeOut([duracion][,callback]), Desaparece
.fadeIn([duracion][,callback])
.fadeTo(duracion, target, callback)
como persiana
haciendo transparente
21!
Ejemplos!
Carga la pgina de rottenpotatoes en Firefox!
Activa firebug. Si no lo tienes an instlado, hazlo: https://
www.getfirebug.com/!
Selecciona el men Scripts de Firebug!
Selecciona el enlace Reload to see all sources!
Prueba ahora en la consola de Firebug las siguientes llamadas:!
this==window;
this.document;
this.document.getElementById('movies'); // Ejemplo de uso de API JSAPI
$('#movies'); // Selecciona toda la tabla con id CSS #movies usando jQuery
jQuery('tr'); // Selecciona todas las filas (<tr>) del documento
$('tr').hide() // En cada tr pone: <tr style="display: none;">. Puedes verlo en el men
// Herramientas->Web Developer Extension->View Source->View Generated Source
22!
Registro de manejadores de
eventos sobre elementos del
DOM!
Eventos y callbacks!
JSAPI permite registrar funciones JavaScript que el browser
llamar cuando ocurran eventos en la interfaz: pulsar botn,
mover ratn sobre elemento, enviar formulario,!
http://www.chipchapin.com/WebTools/JavaScript/example1-04.html!
GSyC!
24!
Tipos de Eventos!
Tipos de eventos aplicables a cualquier elemento:!
o
o
o
o
change !
select (event.which devuelve el texto seleccionado dentro del manejador)!
submit (disparado cuando se enva un formulario)!
!
25!
Ejecucin de callbacks!
El browser llama a un manejador de eventos/
callback cuando se produce el evento sobre el
elemento con el que se asoci el manejador!
Si hay registrado un manejador para el
elemento, o para alguno de sus elementos
ancestros, se ejecutan en cadena antes del
comportamiento predefinido (si existe):!
26!
Ejemplo!
A continuacin aadimos a la pgina principal de
rottenpotatoes un botn para seleccionar pelculas aptas
para menores, sin interaccin con el servidor !
GSyC!
27!
Ejemplo!
A continuacin aadimos a la pgina principal de
rottenpotatoes un botn para seleccionar pelculas aptas
para menores, sin interaccin con el servidor !
app/assets/javascripts/rp.js!
http://pastebin.com/85fZTe4J
RP = {
setup: function() {
// construct new DOM elements
$('<label for="filter" class="explanation">' +
'Restrict to movies suitable for children' +
'</label>' +
'<input type="checkbox" id="filter"/>'
).insertBefore('#movies').change(RP.filter_adult);
},
filter_adult: function () {
// 'this' is JSAPI element that received event (checkbox)
if ($(this).is(':checked')) {
$('#movies tbody tr').each(RP.hide_if_adult_row);
} else {
$('#movies tbody tr').show();
};
},
hide_if_adult_row: function() {
if (! /^G|PG$/i.test($(this).find('td:nth-child(2)').text())) {
$(this).hide();
}
}
}
$(RP.setup);
// when document ready, run setup code
GSyC!
28!
Ejemplo!
A continuacin aadimos a la pgina principal de
rottenpotatoes un botn para seleccionar pelculas aptas
para menores, sin interaccin con el servidor !
app/assets/javascripts/rp.js!
RP = {
setup: function() {
// construct new DOM elements
$('<label for="filter" class="explanation">' +
'Restrict to movies suitable for children' +
'</label>' +
'<input type="checkbox" id="filter"/>'
).insertBefore('#movies').change(RP.filter_adult);
},
filter_adult: function () {
// 'this' is JSAPI element that received event (checkbox)
if ($(this).is(':checked')) {
$('#movies tbody tr').each(RP.hide_if_adult_row);
} else {
$('#movies tbody tr').show();
};
Al cargar la pgina, y
},
por tanto este fichero,
hide_if_adult_row: function() {
pedimos
if (! /^G|PG$/i.test($(this).find('td:nth-child(2)').text()))
{ que se
$(this).hide();
ejecute RP.setup
}
una vez est todo el
}
DOM generado
}
$(RP.setup);
// when document ready, run setup code
GSyC!
29!
Ejemplo!
A continuacin aadimos a la pgina principal de
rottenpotatoes un botn para seleccionar pelculas aptas
para menores, sin interaccin con el servidor !
app/assets/javascripts/rp.js!
RP = {
que interaccionar
setup: function() {
// construct new DOM elements
JavaScript
$('<label for="filter" class="explanation">' +
'Restrict to movies suitable for children' +
'</label>' +
'<input type="checkbox" id="filter"/>'
).insertBefore('#movies').change(RP.filter_adult);
},
filter_adult: function () {
// 'this' is JSAPI element that received event (checkbox)
if ($(this).is(':checked')) {
$('#movies tbody tr').each(RP.hide_if_adult_row);
} else {
$('#movies tbody tr').show();
};
},
hide_if_adult_row: function() {
if (! /^G|PG$/i.test($(this).find('td:nth-child(2)').text())) {
$(this).hide();
}
}
}
$(RP.setup);
// when document ready, run setup code
GSyC!
30!
Ejemplo!
A continuacin aadimos a la pgina principal de
rottenpotatoes un botn para seleccionar pelculas aptas
para menores, sin interaccin con el servidor !
app/assets/javascripts/rp.js!
RP = {
evento change de
setup: function() {
// construct new DOM elements
la checkbox. Mejor change
$('<label for="filter" class="explanation">' +
que click: change se activa
'Restrict to movies suitable for children' +
tambin cuando se selecciona
'</label>' +
'<input type="checkbox" id="filter"/>'
por teclado la checkbox.
).insertBefore('#movies').change(RP.filter_adult);
},
En la callback
filter_adult: function () {
// 'this' is JSAPI element that received event (checkbox)
this es la checkbox JSAPI,
if ($(this).is(':checked')) {
que envolvemos con $(this)
$('#movies tbody tr').each(RP.hide_if_adult_row);
} else {
$('#movies tbody tr').show();
};
},
hide_if_adult_row: function() {
if (! /^G|PG$/i.test($(this).find('td:nth-child(2)').text())) {
$(this).hide();
}
}
}
$(RP.setup);
// when document ready, run setup code
GSyC!
31!
Ejemplo!
A continuacin aadimos a la pgina principal de
rottenpotatoes un botn para seleccionar pelculas aptas
para menores, sin interaccin con el servidor !
app/assets/javascripts/rp.js!
RP = {
setup: function() {
// construct new DOM elements
$('<label for="filter" class="explanation">' +
'Restrict to movies suitable for children' +
'</label>' +
'<input type="checkbox" id="filter"/>'
).insertBefore('#movies').change(RP.filter_adult);
},
filter_adult: function () {
// 'this' is JSAPI element that received event (checkbox)
if ($(this).is(':checked')) {
$('#movies tbody tr').each(RP.hide_if_adult_row);
} else {
Itera sobre cada tr, y lo
$('#movies tbody tr').show();
pasa como this a la funcin
};
del argumento
},
hide_if_adult_row: function() {
if (! /^G|PG$/i.test($(this).find('td:nth-child(2)').text())) {
$(this).hide();
}
}
}
$(RP.setup);
// when document ready, run setup code
GSyC!
32!
Ejemplo!
A continuacin aadimos a la pgina principal de
rottenpotatoes un botn para seleccionar pelculas aptas
para menores, sin interaccin con el servidor !
app/assets/javascripts/rp.js!
RP = {
setup: function() {
// construct new DOM elements
$('<label for="filter" class="explanation">' +
'Restrict to movies suitable for children' +
'</label>' +
'<input type="checkbox" id="filter"/>'
).insertBefore('#movies').change(RP.filter_adult);
},
filter_adult: function () {
// 'this' is JSAPI element that received event (checkbox)
if ($(this).is(':checked')) {
$('#movies tbody tr').each(RP.hide_if_adult_row);
} else {
$('#movies tbody tr').show();
};
},
Muestra todos los
hide_if_adult_row: function() {
if (! /^G|PG$/i.test($(this).find('td:nth-child(2)').text())) {
$(this).hide();
}
}
}
$(RP.setup);
// when document ready, run setup code
GSyC!
tr
33!
Ejemplo!
A continuacin aadimos a la pgina principal de
rottenpotatoes un botn para seleccionar pelculas aptas
para menores, sin interaccin con el servidor !
app/assets/javascripts/rp.js!
RP = {
setup: function() {
// construct new DOM elements
$('<label for="filter" class="explanation">' +
'Restrict to movies suitable for children' +
'</label>' +
'<input type="checkbox" id="filter"/>'
).insertBefore('#movies').change(RP.filter_adult);
},
filter_adult: function () {
// 'this' is JSAPI element that received event (checkbox)
if ($(this).is(':checked')) {
$('#movies tbody tr').each(RP.hide_if_adult_row);
} else {
$('#movies tbody tr').show();
};
},
hide_if_adult_row: function() {
if (! /^G|PG$/i.test($(this).find('td:nth-child(2)').text())) {
$(this).hide();
}
}
2 td del
}
$(RP.setup);
// when document ready, run setup code
GSyC!
tr pasado en this
34!
35!
36!
AJAX!
Introduccin!
En 1998 Microsoft aade el objeto
XmlHttpRequest o xhr a su navegador
Internet Explorer 5 (IE5)!
En 2005 Google Maps es una de las
primeras aplicaciones que demuestra la
potencia de AJAX!
GSyC!
38!
Objeto XmlHttpRequest
(xhr)
El objeto JavaScript XmlHttpRequest, o xhr, que proporcionan
muchos browsers permite realizar RPCs asncronas: la llamada
retorna antes de obtenerse la respuesta del servidor!
Enva un mensaje de peticin HTTP desde JavaScript sin que sea
necesario redibujar toda una pgina al obtener el mensaje de
respuesta!
Programacin basada en
eventos, tambin para xhr!
while (true) {
var event = waitForEvent();
event.callback();
redrawDOM();
}!
Por tanto, la llamada para realizar la peticin xhr no puede ser bloqueante y
quedarse esperando a recibir la respuesta: de hacerlo, bloqueara el bucle de
ejecucin de callbacks, congelando la interaccin con la interfaz!
Por ello la RPC que generamos con xhr retorna inmediatamente, antes de
obtener la respuesta!
Se le pasa una funcin como callback que es llamada por el browser cuando llega la respuesta!
La callback puede reemplazar, cambiar, animar, ya que re se redibuja el DOM en funcin de
los cambios de las callbacks que se van llamando!
GSyC!
40!
'GET',
'http://',
milisegundos,
fn_success,
: fn_error
});
GSyC!
// mtodo HTTP
//
//
//
//
//
//
41!
GSyC!
42!
43!
http://pastebin.com/dW04wY9F
def show
id = params[:id] # retrieve movie ID from URI route
@movie = Movie.find(id) # look up movie by unique ID
render :partial => 'movie', :object => @movie and return if request.xhr?
# will render app/views/movies/show.<extension> by default
end
end
http://pastebin.com/CxxPBQpy
GSyC!
44!
def show
id = params[:id] # retrieve movie ID from URI route
@movie = Movie.find(id) # look up movie by unique ID
render :partial => 'movie', :object => @movie and return if request.xhr?
# will render app/views/movies/show.<extension> by default
end
end
GSyC!
45!
Alternativas
que podra esperar el cliente JavaScript:!
= link_to 'Edit Movie', edit_movie_path(movie)
render= :json
=> @movies
and =>
return
if request.xhr // Llama a @movies.to_json
link_to 'Close',
'', {:id
'closeLink'}
render :xml
=> @movies and return if request.xhr // Llama a @movies.to_xml
def show
id = params[:id] # retrieve movie ID from URI route
@movie = Movie.find(id) # look up movie by unique ID
render :partial => 'movie', :object => @movie and return if request.xhr?
# will render app/views/movies/show.<extension> by default
end
end
GSyC!
46!
def show
id = params[:id] # retrieve movie ID from URI route
@movie = Movie.find(id) # look up movie by unique ID
render :partial => 'movie', :object => @movie and return if request.xhr?
# will render app/views/movies/show.<extension> by default
end
end
47!
48!
RPAjax = {
setup: function() {
// add invisible 'div' to end of page:
$('<div id="movieInfo"></div>').
hide().
appendTo($('body'));
$('#movies a').click(RPAjax.getMovieInfo);
},
getMovieInfo: function() {
$.ajax({type: 'GET',
url: $(this).attr('href'),
timeout: 5000,
success: RPAjax.showMovieInfo,
error: function() { alert('Error!'); }
});
return(false);
},
showMovieInfo: function(data) {
// center a floater 1/2 as wide and 1/4 as tall as screen
var oneFourth = Math.ceil($(window).width() / 4);
$('#movieInfo').
html(data).
css({'left': oneFourth, 'width': 2*oneFourth, 'top': 150}).
show();
// make the Close link in the hidden element work
$('#closeLink').click(RPAjax.hideMovieInfo);
return(false);
},
hideMovieInfo: function() {
$('#movieInfo').hide();
return(false);
},
}
$(RPAjax.setup);
49!
#movieInfo {
padding: 2ex;
position: absolute;
border: 2px double grey;
background: wheat;
}
http://pastebin.com/0WdxM2vp
Y el resultado
mejora visualmente
(ahora parece flotante):!
GSyC!
52!
Depuracin de aplicaciones
AJAX/Rails!
Puedes arrancar firebug y poner puntos
de parada (breakpoints) en el cdigo
JavaScript!
click en el nmero de lnea en la que quieras poner/
quitar un breakpoint!
GSyC!
53!
Usos de JavaScript!
1. Client-side JavaScript: !
2.
3.
GSyC!
55!
Ejemplo: Ember.js!
Ember.js
vs
Rails
Rails
GSyC!
56!
Usos de JavaScript!
1. Client-side JavaScript: !
2.
3.
GSyC!
57!
Ejemplo:!
58!
Usos de JavaScript!
1. Client-side JavaScript: !
2.
Pueden operar
offline!
Frameworks:
Phonegap
+ jQuery
El cdigo JavaScript
en el
browserMobile
usa un servidor delgado, slo para almacenar
Titanium
en la BD, recibiendo
objetos JSON que convierte en HTML (en el browser)!
normalmente con frameworks, como Ember.js, Backbone.js o
Se programan
Angular de Google que soporta el patrn MVC!
En los mviles y tabletas, como plataforma alternativa a
3. Aplicaciones
SaaS pero con
JavaScript en el servidor!
Google/Android,
Apple/iOS:
Frameworks
como
node.js
y extensiones: meteor, express!
Firefox
OS (Firefox)
Open WebOS (HP)
GSyC!
59!
Precauciones!
Rendimiento de
JavaScript/AJAX!
Aparentemente JavaScript+AJAX hace interfaces ms
interactivas, ms dinmicas!
Pero cuidado: !
Hay que descargar jQuery y los ficheros .js, lo que puede hacer que el
usuario perciba que la pgina tarda ms en cargar inicialmente!
Sobre todo en mviles!
El rendimiento de JavaScript puede no ser alto !
61!
Referencias!
Captulo 11 de Engineering Long-Lasting Software.
Armando Fox, David Patterson, beta edition, agosto 2012. !
API de jQuery: http://api.jquery.com/!
Selectores CSS3: http://www.w3.org/TR/selectors/#selectors!
How JavaScript works: introduction to JavaScript and
Browser DOM. Miko Hevery.
http://misko.hevery.com/2010/07/14/how-javascript-works/!
GSyC!
62!