Está en la página 1de 62

DOM y AJAX con jQuery + Rails!

Ingeniera de Sistemas de Informacin! Grado en Ingeniera en Tecnologas de Telecomunicacin! GSyC!

" 2012 Departamento GSyC, URJC!


"Algunos derechos reservados. Este trabajo se distribuye bajo la licencia Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License! "2012 Armando Armando Fox & David Patterson!
" Licensed under Creative Commons AttributionNonCommercial-ShareAlike 3.0 Unported License!

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!

Consejos para aprender !


" Asegrate de tener la barra de herramientas de Firefox instalada (Web Developer Extension)! " Durante tu aprendizaje de JavaScript ten siempre a mano una consola en tu browser para poder probar cdigo!
" En Firefox instala rebug: http://getrebug.com! " En Safari o en Chrome, busca el men de desarrollador y all arranca la consola de JavaScript!

" Para depurar: !


" console.log("hola mundo") " alert("hola") " Depurador de rebug!

" 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://jsddle.net!
GSyC! 4!

Introduccin!

Usos de JavaScript !
1.! Client-side JavaScript: !
" " " " " Cdigo JavaScript que corre en el browser, asociado a la pgina Web! Se usa JavaScript para mejorar la experiencia de usuario de aplicaciones SaaS que siguen el patrn arquitectnico MVC! Se combina JavaScript con HTML y CSS! Es importante que no se mezcle JavaScript con el cdigo HTML! Es importante que el servicio est disponible para cliente no-JavaScript! Pueden operar ofine! El cdigo JavaScript en el browser usa un servidor delgado, slo para almacenar en la BD, recibiendo objetos JSON que convierte en HTML (en el browser)! Se programan normalmente con frameworks, como Ember.js, Backbone.js o Angular de Google que soporta el patrn MVC! Frameworks como node.js y extensiones: meteor, express!

2."

Aplicaciones tipo desktop en el lado del cliente, como Google Docs!


" " "

3."

Aplicaciones SaaS pero con JavaScript en el servidor!


"

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 modicar 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 modicar el documento HTML desde el que se hizo la RPC! !

" Como ejemplos prcticos aprenderemos:!


" a ocultar pelculas no aptas para menores modicando sin intervencin del servidor! " a mostrar una ventana otante con la informacin de una pelcula que ha sido obtenido con AJAX!
GSyC! 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 grca 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 modicar el documento cargado, redibujndolo si hay cambios!
GSyC! 8!

" Las pginas que quieren usar funciones o variables JavaScript tienen que incluir el cdigo JavaScript! " Formas NO recomendadas: mezclado en el body !
http://pastebin.com/sTM4Z8wS !
<html> <head><title>Update Address</title></head> <body> <!-- BAD: embedding scripts directly in page, esp. in body --> <script> <!-- // BAD: "hide" script body in HTML comment // (modern browsers may not see script at all) function checkValid() { // BAD: checkValid is global if !(fieldsValid(getElementById('addr'))) { // BAD: > and < may confuse browser's HTML parser alert('>>> Please fix errors & resubmit. <<<'); } // BAD: "hide" end of HTML comment (l.3) in JS comment: --> </script> <!-- BAD: using HTML attributes for JS event handlers --> <form onsubmit="return checkValid()" id="addr" action="/update"> <input onchange="RP.filter_adult" type="checkbox"/> <!-- BAD: URL using 'javascript:' --> <a href="javascript:back()">Go Back</a> </form> </body> </html>

Dnde poner el cdigo JavaScript? !

GSyC!

9!

Dnde poner el cdigo JavaScript? !


" La forma recomendada es guardar el cdigo en chero aparte y utilizar la etiqueta HTML <script src="url"> para incluirlo en la seccin HEAD del documento, no poniendo cdigo mezclado en el body!
" Misma justicacin que para sacar el estilo a cheros .css! " Helper Rails que genera la etiqueta: javascript_include_tag
'fichero_javascript'

" Los elementos HTML que vayan a iteraccionar con JavaScript:!


" O bien se aaden al DOM en una funcin JavaScript setup() " O bien estn siempre, pero invisibles, usando CSS para que tengan el atributo hidden, y luego en una funcin JavaScript setup() al cargar la pgina se cambia su estilo para que aparezcan! " De cualquiera de las dos formas, si el browser no tiene JavaScript activado no mostrar los elementos HTML que requieren JavaScript, lo que es bueno

" En Rails:!
1." El cdigo JavaScript que escribamos para nuestra aplicacin se pone en cheros 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 chero 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 chero nico para toda la aplicacin en el dir public

GSyC!

10!

El Document Object Model (DOM)!

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"!

" O sea: una representacin estandarizada, en forma de rbol, de los elementos de un documento HTML, XML o XHTML! " Coloquialmente hablamos del DOM de una pgina! " Cada elemento DOM se dene recursivamente pues una de sus propiedades es un array de elementos hijo!
" Por tanto, el nodo DOM que representa el elemento <html> incluye todo el documento, con nodos hijos para <head> y <body>, y <body> tiene nodos hijos <h1>, <div>, ! " Cada elemento puede tener atributos: <img src=>, <a href=>, <div class=>, <span id=>,
GSyC! 12!

DOM !
" Inspeccin del DOM en Firefox: !
" Arrancando rebug, 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!

" Llamando a funciones JavaScript del objeto global (window) se puede recorrer y consultar el rbol DOM de la pgina actual! " Llamando a funciones JavaScript se pueden aadir/ eliminar elementos al rbol DOM, modicar su contenido y modicar/eliminar/aadir atributos (p.ej. id o class) de elementos, lo que provoca que se redibuje la parte afectada de la pgina " Cuando el browser carga una pgina, el HTML de la pgina se parsea para generar su rbol DOM!
" En un browser, el objeto global JavaScript est accesible en la variable global window " En window.document est la raz del rbol DOM de la pgina que est mostrando el browser, cambiando cada vez que carga una nueva.! GSyC!

Acceso al DOM desde JavaScript !

14!

JSAPI !
" El objeto window ofrece algo ms que el DOM! " Ofrece propiedades y funciones para manipular el DOM y otras especcas 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!

" Las implementaciones de JavaScript son bastante similares en los diferentes browsers! " Sin embargo, la API JSAPI no es tan uniforme entre browsers! " Existen varias bibliotecas que recubren JSAPI para homogeneizar: YUI, Prototype, DoJo. La ms usada: jQuery!

GSyC!

15!

jQuery !
"jQuery es una API que recubre JSAPI, proporcionando uniformidad entre browsers!
" Usaremos jQuery y no JSAPI!

"jQuery extiende JSAPI con animaciones, soporte para CSS, eventos y AJAX! "jQuery dene una funcin global: jQuery()
" $() es un alias de jQuery()

GSyC!

16!

Funcin global jQuery(),$()


" jQuery / $() es una funcin sobregarcada (overloaded). Dependiendo de los argumentos que se le pasan hace una cosa u otra!
1." Pasndole un selector de CSS (un string) : ! " Devuelve los elementos del DOM correspondientes al selector CSS que se pasa como argumento, o null si no hay ninguno! " Si se le pasa en un 2 argumento un elemento, slo devuelve los descendientes de ste ! " Si devuelve varios elementos, se itera luego sobre ellos con .each para acceder a cada elemento de la coleccin devuelta! 2." Pasndole HTML (un string):! " Crea el elemento correspondiente al argumento (que ha de tener etiquetas HTML para no confundirse con un selector CSS del caso anterior) y lo devuelve recubierto/envuelto en un objeto jQuery, pero no lo inserta en el DOM (hay funciones para hacerlo)! 3." Pasndole un/unos elemento JSAPI del DOM (ej. document o window):! " Devuelve un objeto jQuery que recubre el elemento del argumento! 4." Pasndole una funcin como argumento! " Ejecuta la funcin una vez se ha cargado todo documento y el DOM est preparado para ser manipulado. Equivalente a $(document).ready(f)
GSyC! 17!

Seleccin de elementos con $('selector-CSS')


! Ejemplos de selectores CSS:!
selector
h1 div#message .red div.red, h1 div#message h1 a.lnk a.lnk:hover

qu selecciona !
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!

Ejemplos de llamadas a $('selector-CSS'):


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 modicando la clase CSS del/de los elementos! 2." Cambiar su contenido modicando 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!

Funciones para elementos seleccionados por jQuery()


Notacin e.func(args) " " " " " " " " " .is(:cond')
':disabled' es una funcin que se aplica a un elemento e devuelto por jQuery(). Ej: $('h1.title').func(args). Si no se indica otra cosa, devuelve el elemento tras aplicrsele la funcin, por lo que se pueden llamar en cascada Comprueba si el elemento est ':checked', ':selected', ':enabled',

.addClass('cssClass'), .removeClass('cssClass'), .hasClass() .insertBefore(elem), .insertAfter(elem), .remove(), .replaceWith(elem), .appendTo(elem) .clone() Devuelve copia recursiva de los descencientes .html(['htmlString']) Devuelve (o pone si hay argumento) el html .text([texto']) Devuelve (o pone si hay argumento) el texto sin etiquetas html
(p.ej. a un <h1> texto </h1> Devuelve o pone el valor del elemento: para textboxes el contenido, para botones la etiqueta, para mens el texto de la opcin seleccionada

.val([val])

.attr('attr' [,nuevoValor]). Ej: $('img').attr('src'), 'http://google.com') .find('selector-CSS') Devuelve elementos hijos seleccionados por selector-CSS. Ej:
$('#movies tr') == $('#movies').find('tr')

GSyC!

20!

Funciones para elementos seleccionados por jQuery()


" " .css('propiedad') Devuelve propiedad CSS del elemento .css({'propiedad':'valor',}) Pone propiedades CSS
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)
Target es un valor de transparencia entre 0.0 y 1.0 GSyC!

como persiana

haciendo transparente

21!

Ejemplos !
" Carga la pgina de rottenpotatoes en Firefox! " Activa rebug. Si no lo tienes an instlado, hazlo: https:// www.getrebug.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

$('tr').show() // Cambia de nuevo el style para que aparezcan pintadas h=$('h1.title') // Selecciona el elemento <h1> de clase CSS .title h.slideUp('slow') // Y ahora lo anima ocultndolo lentamente h.slideDown('slow') // Y ahora lo anima hacindolo aparecer lentamente h.slideToggle(2500) // Si estaba oculto lo hace aparecer, y viceversa theaders=$('#movies th') // los <th> dentro del elemento con id #movies theaders.fadeTo(2000, 0.25) // los vuelve transparentes $('tr').fadeTo(2000,0.25) // y lo mismo con todos los <tr> GSyC! 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,!
" " " Les llamaremos gestores/manejadores de eventos o callbacks! JSAPI dene varios tipos de eventos, que jQuery extiende! Algunos elementos tienen un comportamiento predenido para algunos eventos. Ej. click en un enlace carga la pgina de la url! " http://www.chipchapin.com/WebTools/JavaScript/example1-04.html!

" En las callbacks podemos programar acciones jQuery que modican el DOM ! " Al poderse modicar localmente el DOM, la interaccin es mucho ms dinmica!
" " Los elementos HTML cambian localmente en el navegador como consecuencia de acciones del usuario! Comparado con tener que realizar una nueva peticin HTTP para que el servidor devuelva una nueva pgina con los elementos HTML cambiados, la experiencia del usuario es mucho ms uida!

GSyC!

24!

Cmo registrar eventos! " elemento.tipo-evento(func([event]){})

Registro de manejadores para eventos con jQuery !


Asocia a elemento func como un manejador/callback para tipo-evento. Cuando ocurra tipo-evento sobre elemento, el browser llamar a func(event) pasando en event el evento! !

Tipos de Eventos! " Tipos de eventos aplicables a cualquier elemento:!


o" o" o" o" click, dblclick, mousedown/mouseup, mouseenter/mouseleave keypress (event.which devuelve el cdigo ASCII dentro del manejador)! focus/blur (el elemento obtiene/pierde el foco)! focusin/focusout (el padre del elemento obtiene/pierde el foco)!

" Eventos aplicables a elementos accionables por el usuario (forms, checkboxes, radio buttons, text box, text eld, mens):!
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 predenido (si existe):!
" " " La cadena comienza en el elemento en el que se produce el evento y termina en el objeto global (window)! Si un manejador devuelve true, se ejecuta el siguiente en la cadena! Si el manejador devuelve false, se interrumpe la ejecucin en cadena, y la del comportamiento predenido, que es el ltimo!
GSyC! 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

Inserta el cdigo HTML con

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

Registra callback para el

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

tr

GSyC!

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

tr pasado en this
34!

GSyC!

Comentarios sobre el Ejemplo !


" La checkbox se aade desde la funcin setup(), y sta slo se ejecuta si el browser tiene JavaScript!
" Si la hubiramos puesto en el HTML, los browsers sin JavaScript la mostraran pero no podran interactuar con ella!

" Slo se ha aadido un objeto al mbito global, RP, que dene su propio mbito. Por eso todas las funciones se tienen que llamar por su nombre: RP.fname " Implementacin alternativa menos intrusiva de la ocultacin de pelis para mayores:!
" " " " Si en el servidor marcamos las las de pelculas para adultos:!
%tr{:class => ('adult' unless movie.rating =~ /^G|PG$/)}

Entonces podramos eliminar RP.hide_if_adult_row() Y substituir $('#movies tbody tr').each(RP.hide_if_adult_row); por $('#movies tr.adult').hide(); De esta forma el cdigo JavaScript no se apoya en detalles de la presentacin (Dependemos de que la calicacin est en la 2 columna de la tabla)
GSyC! 35!

Eventos denidos y disparados por el usuario !


" Se pueden denir nuevos eventos utilizando esta otra forma de registrar callbacks para un evento:!
elemento.bind('nuevo-evento', func(event){})

" Y luego se puede llamar a estos eventos explcitamente con trigger " Ejemplo que puedes probar en rebug, en la pgina de rottenpotatoes p.ej.:!
$('#movies').bind('miEvento', function(event, param1, param2){ alert(param1 + "\n" + param2); }); $('#movies').trigger('miEvento',['Custom', 'Event']);
GSyC! 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!
" Genera un mensaje de peticin HTTP normal, al que le aade la cabecera X-Requested-With: XMLHttpRequest!

" Cuando llega la respuesta se llama a una callback que utiliza la respuesta obtenida (p.ej. una vista parcial HTML, o XML, o JSON, texto, o nada) para modicar el DOM de la misma pgina desde la que se hace la peticin! " Al no recargar toda la pgina se tarda menos en mostrar la respuesta y la interfaz ofrece una interaccin ms dinmica! " En jQuery se utiliza $.ajax para usar el objeto xhr
39!

Programacin basada en eventos, tambin para xhr !


" " La programacin en JavaScript para interactuar con la interfaz grca es basada en eventos (event driven): registras callback asociada a un objeto y a un evento, que es llamada por el runtime" JavaScript tiene un nico thread que va ejecutando los manejadores registrados segn van ocurriendo los eventos que los disparan!
" Pseudocdigo del runtime de JavaScript:!

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!

xhr en jQuery: $.ajax


" Con $.ajax realiza en jQuery una llamada XHR! " Es no bloqueante: retorna inmediatamente, y despus, cuando llegue la respuesta HTTP al browser, el runtime de JavaScript llama a la callback registrada! " Ejemplo:
$.ajax({type : url : timeout: success: error }); 'GET', 'http://', milisegundos, fn_success, // mtodo HTTP // // // // // // si tarda ms se llama a error funcin a la que llamar cuando llegue la respuesta funcin a la que llamar si hay errores, p.ej. timeout, servidor no arrancado

: fn_error

GSyC!

41!

Ejemplo de uso de $.ajax()


" Vamos a modicar rottenpotatoes para que los detalles de una pelcula se pidan a nuestro servidor Rails desde JavaScript, usando AJAX, y se muestren en una ventana otante, sin abandonar la pgina index!

GSyC!

42!

Ejemplo de uso de $.ajax()


" Vamos a modicar rottenpotatoes para que los detalles de una pelcula se pidan a nuestro servidor Rails desde JavaScript, usando AJAX, y se muestren en una ventana otante, sin abandonar la pgina index! " Desde una funcin JavaScript se usar xhr para realizar una peticin HTTP a la URL de la accin MoviesController#show
" Podramos crear otra accin pero reaprovecharemos sta accin del controlador!

" Esta accin devolver una vista parcial cuando detecte que la peticin se hace usando xhr, o la vista normal en caso contrario! " Aadiremos un manejador de eventos a los enlaces que hay ahora en la pgina index para ver ms detalles de cada pelcula, y desde el manejador realizaremos la llamada xhr! " Aadiremos un nuevo div a la pgina index para rellenarlo con los datos devueltos por la llamada xhr y le pondremos propiedades CSS que hagan que aparezca en el centro de la pantalla, "otando"!
GSyC! 43!

Ejemplo de uso de $.ajax()


" Vista parcial app/movies/_movie.html.haml que devolver la accin MoviesController#show cuando sea llamada usando xhr!
%p= movie.description = link_to 'Edit Movie', edit_movie_path(movie) = link_to 'Close', '', {:id => 'closeLink'}

http://pastebin.com/dW04wY9F

" Accin del controlador


class MoviesController < ApplicationController 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
44!

GSyC!

Ejemplo de uso de $.ajax()


" Vista parcial app/movies/_movie.html.haml que devolver la accin MoviesController#show cuando sea llamada usando xhr!
%p= movie.description = link_to 'Edit Movie', edit_movie_path(movie) = link_to 'Close', '', {:id => 'closeLink'}

" Accin del controlador

class MoviesController < ApplicationController X-Requested-With: XMLHttpRequest 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

El mtodo xhr? del objeto request del controlador devuelve true si en el mensaje de peticin HTTP se ha includo la cabecera

GSyC!

45!

Ejemplo de uso de $.ajax()


" Vista parcial app/movies/_movie.html.haml que devolver la accin MoviesController#show cuando sea llamada usando xhr!
%p= movie.description

Alternativas que podra esperar el cliente JavaScript:! = link_to 'Edit Movie', edit_movie_path(movie)
:text => @movie.title and return if request.xhr render :nothing => true and return if request.xhr " Accin del controlador
render

render => @movies and => return if request.xhr // Llama a @movies.to_json = :json link_to 'Close', '', {:id 'closeLink'} render :xml => @movies and return if request.xhr // Llama a @movies.to_xml

class MoviesController < ApplicationController 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!

Ejemplo de uso de $.ajax()


" Vista parcial app/movies/_movie.html.haml que devolver la accin MoviesController#show cuando sea llamada usando xhr!
%p= movie.description = link_to 'Edit Movie', edit_movie_path(movie) = link_to 'Close', '', {:id => 'closeLink'}

" Accin del controlador


class MoviesController < ApplicationController 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

Si no es una peticin xhr se sirve la vista normal


GSyC! 47!

Ejemplo de uso de $.ajax()


" Nuevo chero JavaScript app/assets/javascripts/rpajax.js
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); }, } http://pastebin.com/yhmPC4Ki $(RPAjax.setup);

48!

Ejemplo de uso de $.ajax()


" Nuevo chero JavaScript app/assets/javascripts/rpajax.js
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);

Aadimos nuevo <div> al final de la pgina, con id para poderle poner CSS Asociamos callback para cuando se haga click en cada uno de los elementos <a> de la tabla #movies

49!

Ejemplo de uso de $.ajax()


" Nuevo chero JavaScript app/assets/javascripts/rpajax.js
RPAjax = { setup: function() { // add invisible 'div' to end of page: $('<div id="movieInfo"></div>'). this es el elemento sobre el hide(). appendTo($('body')); que se ha disparado el evento: un $('#movies a').click(RPAjax.getMovieInfo); '#movies a' == <a href="url"> }, 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); 50!

La url la sacamos del actual enlace en el HTML: <a href="url"> Paramos la cadena de ejecucin de callbacks: no queremos que se ejecute la accin por defecto del link: pedir la url (otra vez!)

Ejemplo de uso de $.ajax()


" Nuevo chero JavaScript app/assets/javascripts/rpajax.js
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); Ponemos el HTML en el $('#movieInfo'). <div id="movieInfo"> html(data). css({'left': oneFourth, 'width': 2*oneFourth, 'top': 150}). show(); Modificamos sus propiedades CSS // make the Close link in the hidden element work dndole dimensiones relativas $('#closeLink').click(RPAjax.hideMovieInfo); al tamao de la ventana, y mostramos return(false); el <div id="movieInfo"> }, hideMovieInfo: function() { Asociamos callback al enlace close de la ventana $('#movieInfo').hide(); return(false); }, } $(RPAjax.setup); 51!

HTML devuelto en la vista parcial _movie.html.haml

Ejemplo de uso de $.ajax()


" El resultado!

" Aadimos coordenadas absolutas, color, borde,:!


app/assets/stylesheets/app
#movieInfo { padding: 2ex; position: absolute; border: 2px double grey; background: wheat; } http://pastebin.com/0WdxM2vp

" Y el resultado mejora visualmente (ahora parece otante):!


GSyC! 52!

Depuracin de aplicaciones# AJAX/Rails !


" Puedes arrancar rebug y poner puntos de parada (breakpoints) en el cdigo JavaScript!
" click en el nmero de lnea en la que quieras poner/ quitar un breakpoint!

" Y en el depurador de rails puedes poner puntos de parada en el cdigo Rails. !


" Recuerda:!
1." Arrancar rails server debug 2." Insertar llamada a debugger en la lnea en la que quieras interrumpir la ejecucin!

GSyC!

53!

Otros usos de JavaScript!

Usos de JavaScript !
1.! Client-side JavaScript: !
" " " " " Cdigo JavaScript que corre en el browser, asociado a la pgina Web! Se usa JavaScript para mejorar la experiencia de usuario de aplicaciones SaaS que siguen el patrn arquitectnico MVC! Se combina JavaScrpt con HTML y CSS! Es importante que no se mezcle JavaScript con el cdigo HTML! Es importante que el servicio est disponible para cliente no-JavaScript! Pueden operar ofine! El cdigo JavaScript en el browser usa un servidor delgado, slo para almacenar en la BD, recibiendo objetos JSON que convierte en HTML (en el browser)! Se programan normalmente con frameworks, como Ember.js, Backbone.js o Angular de Google que soporta el patrn MVC! Frameworks como node.js y extensiones: meteor, express!

2."

Aplicaciones tipo desktop en el lado del cliente, como Google Docs!


" " "

3."

Aplicaciones SaaS pero con JavaScript en el servidor!


"

GSyC!

55!

Ejemplo: Ember.js !
Ember.js vs Rails

Rails

GSyC!

56!

Usos de JavaScript !
1.! Client-side JavaScript: !
" " " " " Cdigo JavaScript que corre en el browser, asociado a la pgina Web! Se usa JavaScript para mejorar la experiencia de usuario de aplicaciones SaaS que siguen el patrn arquitectnico MVC! Se combina JavaScrpt con HTML y CSS! Es importante que no se mezcle JavaScript con el cdigo HTML! Es importante que el servicio est disponible para cliente no-JavaScript! Pueden operar ofine! El cdigo JavaScript en el browser usa un servidor delgado, slo para almacenar en la BD, recibiendo objetos JSON que convierte en HTML (en el browser)! Se programan normalmente con frameworks, como Ember.js, Backbone.js o Angular de Google que soporta el patrn MVC! Frameworks como node.js y extensiones: meteor, express!

2."

Aplicaciones tipo desktop en el lado del cliente, como Google Docs!


" " "

3."

Aplicaciones SaaS pero con JavaScript en el servidor!


"

GSyC!

57!

Ejemplo: !
" " Biblioteca JavaScript para programar servidores! En lugar de lanzar un nuevo proceso en el servidor para cada peticin como hacen por omisin Rails/Django, las peticiones se encolan y son atendidas por un solo thread! Ventaja: mayor rendimiento (peticiones/s) al no haber coste en tiempo de ejecucin para crear procesos ni para cambiar de contexto entre ellos! Inconveniente: ms difcil de programar, pues las llamadas han de ser no bloqueantes, teniendo que registrar callbacks! Ejemplo de servidor HTTP programado con node.js:
var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World\n'); }).listen(1337, '127.0.0.1'); console.log('Server running at http://127.0.0.1:1337/');

" " "

" "

Hay frameworks sobre node.js: meteor, express,! Yahoo Mojito es un framework hbrido: permite elegir entre generar HTML en el servidor (node.js) o en el browser (recibe JSON y convierte a HTML en el browser)!
GSyC! 58!

Usos de JavaScript !
1.! Client-side JavaScript: !
" " " " " Cdigo JavaScript que corre en el browser, asociado a la pgina Web! Se usa JavaScript para mejorar la experiencia de usuario de aplicaciones SaaS que el patrn MVC! Y siguen an hay ms arquitectnico usos de JavaScript: Se combina JavaScrpt con HTML y CSS! " E n los mviles y tabletas , para desarrollar una sla vez (en ! JavaScript) Es importante que no se mezcle JavaScript con el cdigo HTML y desplegar/ejecutar sobre diversas plataformas mviles como Es importante que el servicio est disponible para cliente no-JavaScript! Android, iPhone, BlackBerry,

2."

Aplicaciones tipo desktop en el lado del cliente, como Google Docs!


" "

Pueden operar ofine! Frameworks: !" Phonegap + jQuery Mobile El cdigo JavaScript en el browser usa un servidor delgado, slo para almacenar !" Titanium en la BD, recibiendo objetos JSON que convierte en HTML (en el browser)! !" " Se programan normalmente con frameworks, como Ember.js, Backbone.js o 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 cheros .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 !

" Por qu no programar casi todo en el cliente y dejar para el servidor el acceso a la BD y poco ms, como hacen Ember, Backbone,?!
" " " " No es evidente cul es la mejor solucin! Hay mucha actividad en la actualidad! El cdigo JavaScript en el cliente podra hacer queries demasiado complejas, lo que puede evitarse con APIs bien pensadas! Por otro lado, el rendimiento de la aplicacin pasa a depender de la plataforma en la que corre el browser, lo que ocurre menos si la funcionalidad est sobre todo implementada en el servidor!
GSyC! 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. Mi$ko Hevery.
http://misko.hevery.com/2010/07/14/how-javascript-works/!

" jQuery: Novice to Ninja. Earle Castledine, Craig Sharkie. 2nd ed. Site Point 2012 (Disponible en Safari)! " JavaScript. The Denitive Guide: Activate Your Web Pages 6th ed.. David Flanagan. O'Reilly 2011. (Disponible en Safari). !

GSyC!

62!