You are on page 1of 184

Table

of Contents
1. Introduction 1.1
2. Entorno de trabajo 1.2
1. Software 1.2.1
2. Configuracin de Sublime Text 1.2.2
3.
4. Multimedia 2.1
1. Imagen 2.1.1
2. Video 2.1.2
3. Audio 2.1.3
4. Qu funciona en la web 2.1.4
5.
6. La Web actual 3.1
1. La Web actual 3.1.1
2. Proyecto Web bsica 3.1.2
3. Tiempo de carga 3.1.3
7.
8. CSS avanzado 4.1
1. Lenguajes de preprocesado: Sass 4.1.1
2. Uso de Bootstrap 4.1.2
9.
10. JavaScript 5.1
1. Caractersticas generales 5.1.1
2. linters 5.1.2
3. jQuery 5.1.3
1. Efectos en jQuery 5.1.3.1
2. html y jQuery 5.1.3.2
3. Eventos 5.1.3.3
4. Ajax 5.1.3.4
5. Adios jQuery? 5.1.3.5
11.
12. Node.js 6.1
1. Introduccin a Node.js 6.1.1
2. Crear una librera en node.js 6.1.2
3. Arquitectura de una API REST 6.1.3
4. Creacin de una API con node.js 6.1.4
13.
14. SPA 7.1
1. Arquitectura de un SPA 7.1.1
2. PhoneGap 7.1.2
15.
16. Web Components 8.1
1. Entorno de desarrollo mediante Webpack 8.1.1
2. Caractersticas de ES2015 8.1.2
3. Evolucin del CSS 8.1.3
4. Reactjs 8.1.4
5. Real Time 8.1.5
17.
18. Proyectos solucionados 9.1
1. Proyecto Web bsica 9.1.1
1
2. Web con bootstrap y gulp 9.1.2
3. React.js con material-ui 9.1.3

2
Introduction

Introduction
Introduccin
Objetivos del curso
Configurar entornos reales de trabajo para desarrollo web

Editor de cdigo
Control de versiones
Automatizacin de tareas

Desarrollo Web actual

Pginas adaptables
Criterio Mobile First
Frameworks de CSS: Bootstrap y Material Design
Frameworks de JavaScript: React.js

Conocer arquitecturas de desarrollo de software

MEAN stack
Real time
Aplicaciones hbridas para mviles
Web Components

Apreciar la evolucin en el desarrollo del software

Tests: Mocha, Code coverage, Travis...


CSS -> Preprocesado de CSSS -> Frameworks de CSS -> CSS Modules...
Uso de transpilers y evolucin actual de JavaScript

Conocimientos previos
html, css y js bsico
Puedes seguir este tutorial para html y css bsico
Empezaremos con un ejercicio prctico:
Nos familiarizamos con Sublime Text
Practicamos con Emmet
Repasamos Chrome Developer Tools
Repasamos etiquetas html5 y css

Relacin con el currculo de DAW


Sistemas informticos

Utilizaremos comandos de consola de Linux


Ejecucin de servicios
Aadir repositorios e instalar paquetes

3
Introduction

Bases de datos

Utilizaremos una base documental MongoDB (la opcin ms extendida)


No aparece en el currculo!!!
Quiz algn ejercicio con MySql y phpMyAmin

Lenguaje de marcas

Crear y validar documentos en html

Programacin

Utilizaremos elementos y estructuras propias de los lenguajes de programacin, mediante


JavaScript

Entornos de desarrollo

Arquitectura de aplicaciones Web


Api REST
Aplicaciones para mviles
Instalacin y uso de entornos de desarrollo
Configuracin y uso de Sublime Text
Otras opciones
Entornos de optimizacin y automatizacin de tareas mediante con node.js
Pruebas mediante Mocha
Integracin continua mediante Travis CI
Code Coverage con istanbul
Control de versiones con Git y GitHub

Despliegue y aplicaciones Web

Instalacin de un servidor Web


Express y node.js
Control de versiones con Git y GitHub

Desarrollo Web en entorno Servidor

Arquitectura de aplicaciones Web


Api REST
Soluciones hbridas
Soluciones en tiempo real
Nada de etiquetas embebidas: asp, php...!

Desarrollo Web en entorno Cliente

Repaso general de todo el temario

Diseo de interfaces Web

Repaso general de todo el temario

Cmo trabajar
4
Introduction

Roles

Quin es el profesor?
Persona con conocimientos lmitados
Tiempo de respuesta: horas? das?
Buen orientador

Quin es stackoverflow?
Multitud de personas con mltiples conocimientos (ver tags)
Tiempo de respuesta: minutos?
La mejor herramienta junto con GitHub para ir haciendo curriculum

Trabajo por proyectos

Complicado con los mdulos si los hacemos "estancos"


Fomenta la creatividad y el trabajo en equipo
Que trabajen los alumnos. Es ms interactivo y menos cansado :-)
Los controlamos mediante GitHub o Bitbucket
Repositorios privados o pblicos
PR en vez de copiarse del compaero
Tiene que estar claro como funciona desde 1 y no hay otra forma que haciendo cdigo

Otras ideas

Servidor en la nube
So You Start con Vesta
Primer portfolio del alumno
Entorno real
Virtualiza con Docker
Ms rpido
Se puede montar un servidor de imgenes Docker en el propio centro
Uso de gestores de contenidos (Wordpress, Joomla, Magento, Prestashop)...

Documentacin
Generada con Gitbook

Para generar las slides, pdf, epub o mobi

Es necesario tener instalado calibre

git clone git@github.com:juanda99/curso-webapps.git


5
Introduction

cd curso-webapps
gitbook install
npm install -g gitbook-cli
npm install
npm run slides
npm run pdf
npm run epub
npm run mobi

Libro online con generacin de pdf, epub y mobi

6
Entorno de trabajo

Entorno de trabajo
Entorno de trabajo
Los objetivos de este captulo son los siguientes:

Tener una lista de software necesario y su procedimiento de instalacin, de modo que se pueda
replicar de forma rpida.
Tener anotados todos los ajustes, configuraciones y plugins que nos van a hacer falta en los
distintos programas (especialmente en Sublime Text) que utilizaremos a lo largo de todo el
curso.

7
Software

Software
Instalacin y configuracin del software
nvm
Instalaremos y utilizaremos node va nvm (node virtual manager)

Esto nos permitir:

Poder cambiar de versin de node de forma transparente


Evitar tener que hacer sudo cuando instalemos paquetes de forma global

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.1/install.

Instalar una versin de node:

nvm install 5.0

Ver las versiones que hay instaladas:

nvm ls

Usar una versin en particular:

nvm use 5.0

Usar una versin en particular siempre que abrimos un shell:

nvm alias default 5.0

node
La otra opcin sera instalar directamente node:

curl -sL https://deb.nodesource.com/setup_5.x | sudo -E bash -


sudo apt-get install -y nodejs
sudo apt-get install build-essential

Comprobamos que est instalado:

npm -v
node -v

git
Instalacin de git:

sudo apt-get update


sudo apt-get install git

8
Software

Configuracin necesaria para cada commit que haga:

git config --global user.name "Your Name"


git config --global user.email "youremail@domain.com"

Opcionalmente el editor (si no me gusta el que hay por defecto):

git config --global core.editor vi

Configuracin de git

Git tiene 3 niveles de configuracin, cada nivel sobreescribe el anterior:

Para todos los usuarios: /etc/gitconfig


Para un usuario: ~/.gitconfig (opcin --global)
Para un repositorio: .git/config

Para ver los parmetros configurados:

git config --list

Viene bien tener una chuleta de comandos de Git

Configuracin de GitHub

Nos registramos en Github


Accedemos a nuestra cuenta

Vamos a los settings y asociamos una ssh-key

Evitaremos introducir usuario/contrasea en cada git push

Como creamos nuestra ssh-key:

ssh-keygen

Copiaremos el contenido de ~/.ssh/id_rsa.pub a una nueva clave ssh en GitHub

Instalacin de zsh
Algunos prefieren fish

Otros son fieles a bash

sudo apt-get install zsh


chsh -s $(which zsh)

Instalo oh-my-zsh

Aado el plugin para nvm y git

Instalacin de Sublime Text 3


Lo veremos en el siguiente punto.

9
Software

La eleccin de un IDE o un editor de cdigo no es trivial y la configuracin del mismo para explotar
todas sus posibilidades tampoco.

Instalacin de Google Chrome


Desde la web

Instalacin de Adobe Brackets


Web de referencia
Es un editor exclusivamente para web (js, html, css)
Ms informacin

Instalacin de Gnome Shell


Como instalarlo y configurarlo
Instalaremos tambin un terminal: Guake

Instalacin de MongoDB
Instalaremos primero mongodb:

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv EA312927


echo "deb http://repo.mongodb.org/apt/ubuntu trusty/mongodb-org/3.2 multiverse
sudo apt-get update
sudo apt-get install -y mongodb-org

El servicio se levanta como otros servicios de Linux:

sudo service mongod start

Y para entrar a su consola, mediante mongo, o mediante algn gui como por ejemplo
Robomongo, que tambin podemos instalar desde su web.

Instalacin de Android Studio


Lo podemos instalar de forma manual:
Descargar software
Instalar dependencias como Java y libreras varias
Mediante ubuntu-make (antes Ubuntu developer tool center)
cli para descargar e instalar la ltima versin de las herramientas ms populares de
desarrollo
Gestiona las dependencias

ubuntu-make

Instalacin de umake:

sudo add-apt-repository ppa:ubuntu-desktop/ubuntu-make


sudo apt-get update
sudo apt-get install ubuntu-make

10
Software

Uso de umake (ver lista de software)

umake -h
# por ejemplo en IDES
umake ide -h

Instalacin de Android Studio:

umake android # umake android android-studio

Una vez instalado ejecutamos studio.sh que nos instalar el SDK.

Variables de Shell

Fichero $HOME/.zshrc para el shell zsh:

export ANDROID_HOME='/home/usuario/Android/Sdk'
path+=('/home/usuario/Android/Sdk/tools' '/home/usuario/Android/Sdk/platfo

Aado tambin el repositorio de los binarios de npm (lo utiliza Sublime Text y al usar zsh hay
que drselo). Fichero $HOME/.zshenv:

path+=('/home/usuario/.nvm/versions/node/v5.0.0/bin/')

Test de funcionamiento

Cierra y vuelve a abrir el shell


Ejecuta un comando como android avd

11
Configuracin de Sublime Text

Configuracin de Sublime Text


Configuracin de Sublime Text
Editores de cdigo
Sublime Text, Atom, Brackets

IDE: Integrated Desktop Environment (

WebStorm
NetBeans, Eclipse, Android Studio
Visual Studio Code?

Un IDE tiene muchas cosas "out of the box":

Terminal
VCS (Version Control System)
Task Runner (Grunt, gulp...)
Debug, testing...

Un editor de cdigo tiene:


Ventajas:
Ms ligero
Lo configuras a tu manera (plugins)
Desventajas:
Trabajo de configuracin
No est integrado

Instalacin de Sublime Text 3


Instalacin:

sudo add-apt-repository ppa:webupd8team/sublime-text-3


sudo apt-get update
sudo apt-get install sublime-text-installer

Instalamos package control


Necesario para instalar cualquier plugin posteriormente
Podemos hacer una bsqueda de plugins que nos interesen desde su web
Chuleta con los comandos ms usados

Plugins para Sublime Text


AutoFileName: para autocompletar el nombre de ficheros
HTML Prettify: Formaterado de js, html y css. Pulsando CTRL+MAYS+H
Git gutter: para ver las modificaciones del cdigo respecto al ltimo commit. El resto de
interaccin con Git mediante consola (aunque existen plugins)
markdown editing: Para editar cdigo en markdown

12
Configuracin de Sublime Text

markdown preview: Para hacer vista previa del markdown

Bootstrap 3 Snippets: Pulsando bs3


jQuery: snippets para jQuery
Emmet: Ayuda para escribir html y css.
w3cvalidators: Para validacin de cdigo html

nodejs: para autocompletado

ExpressComplete: para autocompletado de Express

aget : app.get("/", function(req,res) { } )


apost : app.post("/", function(req,res) { } )
aput : app.put("/", function(req,res) { } )
adel : app.delete("/", function(req,res) { } )

sidebar enhacements: ofrece ms opciones en el men lateral


El men lateral aparece y desaparece mediante CTRL + K + B
Si no aparecen las nuevas opciones es por haber abierto un fichero con sublime en vez
de una carpeta!!

Sublimelinter: framework para linters


SublimeLinter-csslint: linter para CSS
SublimeLinter-contrib-eslint: linter para js segn eslint

Mocha Snippets:

desc<tab>
befr<tab>
aftr<tab>
suite<tab>
test<tab>

Aadiremos snippets de React a Sublime para poder trabajar con React ms rpido

Babel como Syntax Highlighter. Habr que configurar los ficheros con extensin js para que lo
usen por defecto, ver https://packagecontrol.io/packages/Babel

Snippets para Sublime


Muchos de los plugins que hemos utilizado incorporan snippets

Para ver y poder modificar los snippets utilizaremos el paquete PackageResourceViewer. Ms


info

Crear y compartir snippets (via GitHub)

Configuracin tabulaciones
Necesario para lenguajes como Python
En nuestro caso por criterio de formato de cdigo
Fichero Preferences->Settings - Users:

13
Configuracin de Sublime Text

{
"tab_size": 2,
"translate_tabs_to_spaces": true
}

14
Multimedia

Multimedia

15
Imagen

Imagen
Imgenes
Introduccin
Las imgenes un elemento clave para una web bien diseada
Las pginas web atractivas se encuentran, no se hacen:
Bsqueda de imgenes
Bsqueda de iconos
Bsqueda de patterns

Logotipos, imgenes y diseo


El diseo es clave para una web
Dnde encontrar buenos diseadores?
Dnde darse a conocer como diseador?
Dribble
Behance: portfolios online de diseadores en la nube de Adobe.
The awards for design, creativity and innovation on the Internet

Bancos de fotografas
http://www.gettyimages.es/
http://www.shutterstock.com/
http://www.istockphoto.com/
http://www.fotolia.com
http://www.bigstockphoto.com/
http://www.sxc.hu/ (gratuito)

Caso prctico
La eleccin de imgenes puede llevar mucho tiempo y es vital para el aspecto final de nuestra
web.
Ejemplos de imgenes para webs de accidentes de trfico:
http://abogadoaccidentetrafico.es/
http://www.marianosanchez.com/
http://www.solernaharro.com/
Qu tipo de imgenes utilizaras tu?
El enfoque del cliente es importante para el desarrollo de la web

Optimizacin de imgenes
Podemos utilizar PageSpeed de Google
Podemos instalar algn software como trimage:

sudo apt-get install trimage

16
Imagen

Retocar imgenes
En ocasiones es bueno retocar las imgenes:
Brillo, contraste, reduccin de ruido
Recortar la imagen para centrar la atencin en una parte de ella.
Alinear horizonte, ojos rojos....
Utilizaremos programas como photoshop o gimp.

Tipos de imgenes
Imgenes de mapa de bits:
Estn formadas por un conjunto de puntos (pxeles) contenidos en una tabla.
Cada uno de estos puntos tiene un valor o ms que describe su color.
Se modifican mediante Gimp o Photoshop

Imgenes vectoriales:
Representaciones de entidades geomtricas tales como crculos, rectngulos o segmentos.
Estn representadas por frmulas matemticas (un rectngulo est definido por dos
puntos; un crculo, por un centro y un radio...)
Se modifican mediante Inkscape o CorelDraw

Qu tipo de imgenes utilizamos?


Las imgenes de mapas de bits se pixelan.
Las imgenes vectoriales son ms simples, aunque la superposicin de formas simples pueden
producir resultados impresionantes.
Las fotografas sern siempre mapas de bits
Las imgenes vectoriales se introducen en html5 por medio del formato svg (hasta ahora
mediante Flash).
Interacccionar entre imgenes vectoriales y JS es sencillo.

Imgenes en dispositivos
til para dar un aspecto ms moderno y tecnolgico
Muy usado en programas de software, mostrando por ejemplo una aplicacin dentro de un ipad
Desde nuestro SO podemos capturar la pantalla o ventana actual y existen servicios que nos
generan nuestra imagen en un dispositivo fsico:
http://placeit.breezi.com
http://mockuphone.com
http://developer.android.com/distribute/promote/device-art.html
Tambin podemos hacerlo a mano:
http://goo.gl/aLuT6e

Tratamiento de imgenes desde consola


Instalaremos el paquete imagemagick para tratar las imgenes:

apt-get install imagemagick

Cambiar formato de una imagen:

$ convert rose.jpg rose.png


17
Imagen

Especificar el nivel de compresin para imgenes jpg (de 0 a 100, por defecto 92):

convert howtogeek.png -quality 95 howtogeek.jpg

Cambiar el tamao de las imgenes:


En este caso se sobreescribe la imagen original
La imagen intentar guardar la proporcin

convert example.png -resize 200x100 example.png

En este caso la imagen no guardar la proporcin (por la exclamacin):

convert example.png -resize 200x100! example.png

Ancho 200, el alto segn proporciones de la imagen:

convert example.png -resize 200 example.png

Alto 100, ancho segn proporciones de la imagen:

convert example.png -resize x100 example.png

Procesos en batch:
En este caso rotamos todas las imgenes de tipo png del directorio actual 90 y las
guardamos con el prefijo "rotated"

for file in *.png; do convert $file -rotate 90 rotated-$file; done

Tambin podremos realizar efectos como marcas de agua...


Para ms informacin, ejecutamos "man convert"

18
Video

Video
Video
Historia
Antes de html5 no haba ningn estndar para el video.
Se recurra a plugins como QuickTime, RealPlayer o Flash.
Ahora es tan sencillo como aadir la etiqueta video:

<video src="video.webm" controls>


</video>

El navegador mostrar los controles bsicos para reproducir o pausar el video.

Insercin de video
Desgraciadamente la etiqueta video no funciona en todos los navegadores
Se pueden indicar varios sources por si el navegador no es capaz de reproducir uno de ellos
El navegador lo intentar con el primero, luego con el segundo....

<!DOCTYPE HTML>
<html>
<body>

<video width="320" height="240" controls="controls">


<source src="movie.mp4" type="video/mp4">
<source src="movie.ogg" type="video/ogg">
<source src="movie.webm" type="video/webm">
Your browser does not support the video tag.
</video>

</body>
</html>

Si indicamos el type en el video mejoraremos el rendimiento ya que el navegador sabe si puede


reproducir ese video o no sin tener que intentarlo:

<source lang="html4strict">
<video controls>
<source src="devstories.webm"
type='video/webm;codecs="vp8, vorbis"'/>
<source src="devstories.mp4"
type='video/mp4;codecs="avc1.42E01E, mp4a.40.2"'/>
</video>
</source>

Video containers

19
Video

Muchas veces pensamos en un fichero .avi o .mp4 como si fuera un video, pero realmente es un
formato contenedor.
Un fichero contenedor es como un fichero .zip y en el caso del video contiene un stream de
video y otro de audio.
El fichero contenedor define como almacenar los streams de audio y video en un solo fichero.
Aunque no es tan fcil: No todos los streams de video son compatibles con todos los ficheros
contenedores.

Video Codecs
Los streams de video y audio se codifican y se almacenan en un container.
A la hora de reproducirlos, primero el reproductor debe interpretar el formato del container y
luego decodificar el video y el audio
Cuando hablamos de un codec de video nos referimos tanto un algoritmo de COdificacin
como al de DECodificacin
Los codec de video ms populares son H264, Theora y VP8.

H264

Tambin se conoce como MPEG-4 Advanced Video Coding.


Tiene diferentes perfiles de codificacin en funcin de la calidad del video final generado:
Baseline, Main y High profiles
El H264 est embebido en los containers ms populares como mp4 y mkv.
Tiene licencia: si codificas algo en mp4 y lo compartes con el mundo, pueden exigirte royalties.

THEORA

Sin ningn tipo de patentes


En cualquier container, normalmente en ficheros .ogg

VP8

Comprado por Google y liberada la patente.

20
Audio

Audio
Audio
Voces de Audio
Pueden ser caras:
250 euros por 5 minutos de voz.
El equipo de audio no lo pones tu :-)
http://www.voices.com/ Elegir una voz
Te suena?

Embedded video: https://www.youtube.com/watch?v=07wVo1hnmdQ

Audio Codecs
Como los codecs de video existen con o sin prdida
Como en los de video, para la web nos interesan los que tienen perdida (pero a su vez menor
peso)
Nos centraremos en los codecs generales (hay especficos por ejemplo para telefona).
Al descodificar el audio mandamos los datos del stream de audio a los altavoces

Los audios tienen canales (los videos no): cada altavoz se alimenta de un channel del stream de
audio.
Los codecs de propsito general codifican normalmente 2 canales.
En la web se utilizan exlusivamente tres codecs: MP3, AAC y Vorbis.

MP3

Formalmente llamado MPEG-1 Audio Layer 3


Hasta 2 canales de sonido
Distintos bitrates 64kbps, 128kbps, 192kbps
A mayor bitrate el fichero ser ms pesado y tendr ms calidad de audio

El bitrate y la calidad de audio no tienen una relacin lineal:


128kbps se oye con ms del doble de calidad que 64kbps
256k no se oye con el doble de calidad que 128kbps
Podemos codificar con un bitrate constante o variable (por ej. codificando a un bitrate bajo los
silencios de audio).
Tiene patentes, por eso Linux no lo reproduce por defecto.

AAC

Formalmente llamado Advanced Audio Coding


Hasta 64 canales de sonido
Estandarizado por Apple en 1997. Lo utilizo como formato por defecto para su iTunes Store.
Diseado para dar mayor calidad de audio que MP3 al mismo bitrate
Sin lmite de bitrate (MP3 lo tiene en 320kbps)
La librera libre para codificar en AAC se llama FAAC.
21
Audio

Usa profiles, de forma similar a MP4.

VORBIS

Denominado a veces OGG-VORBIS pero OGG es el container


Suele ir embebido en ficheros ogg o webm pero tambin puede ir en mp4, mkv
Soporta un gran nmero de canales de sonido

22
Qu funciona en la web

Qu funciona en la web
Qu funciona en la Web?
Formatos para la web
En el 2010 por temas de compatibilidad era necesario usar ms de un formato
MP4: Principalmente para IE y Safari
WebM: Opera, Firefox y Google Chrome
Ogg: Opera, Firefox y Google Chrome
El formato WebM se basa en una versin restringida del formato contenedor Matroska. Siempre
utiliza el cdec de vdeo VP8 y el cdec de audio Vorbis.

Ogg en principio poda ser prescindible. WebM da mejor relacin calidad-compresin.

Actualmente con usar mp4 es suficiente.

Configuracin servidor web


El servidor web tiene que tener los mime types configurados para la reproduccin de videos en
los navegadodores
Ser lo que enve en el header como content-type y que el navegador puede requerir.
En el servidor web Apache lo haremos en el fichero .htaccess o en el httpd.conf/apache2.conf:

AddType video/ogg .ogv


AddType video/mp4 .mp4
AddType video/webm .webm

Codificacin de Vdeo
livav o ffmpeg? Ver resumen de problemtica
Por defecto Ubuntu funciona con livav.
Instalacin de ffmpeg
Codificacin con H.264
Codificacin con WebM y Ogg
Otra opcin es usar handbrake (est en los repositorios)

Videos responsivos
css habitual

Declarar dimensiones "estticas" no es buena idea:

<video width="400" height="300" ....

Utilizaremos porcentajes: el vdeo se adaptar a su elemento contendedor.

En html5 es bueno definir solo la anchura para que el vdeo mantenga su proporcin:

23
Qu funciona en la web

<video width="100%" ....

Mediante css:

video {
width: 100% !important;
height: auto !important;
}

Vdeos de youtube, vimeo mediante iframe

Cdigo insercin vdeos youtube:

<iframe width="640" height="480"


src="http://www.youtube.com/embed/oDlsOyPKUTM"
frameborder="0" allowfullscreen>
</iframe>

Cdigo insercin vdeos vimeo:

<iframe src="http://player.vimeo.com/video/57444237" width="500"


height="281" frameborder="0" webkitAllowFullScreen
mozallowfullscreen allowFullScreen>
</iframe>

Vdeos de youtube, vimeo mediante object

Tambin se puede usar object y embed para insertar cdigo no html. Por ejemplo youtube con
Flash:

<object width="640" height="480">


<param name="movie" value="http://www.youtube.com/v/
oDlsOyPKUTM?hl=es_ES&amp;version=3"></param>
<param name="allowFullScreen" value="true"></param>
<param name="allowscriptaccess" value="always"></param>
<embed src="http://www.youtube.com/v/oDlsOyPKUTM?hl=es_ES&amp;version=3"
type="application/x-shockwave-flash"
width="640" height="480" allowscriptaccess="always" allowfullscreen="tru
</embed>
</object>

En desuso

Vdeo responsivo por iframe

Si no se especifica las dimensiones de un elemento tipo iframe, embed, object y canvas, en


navegador lo dimensiona como 300x150px
No se puede utilizar la misma solucin que con la etiqueta video de dar una anchura de un
100%: el navegador pondra una altura de 150px que sera normalmente demasiado pequea.
Ver solucin

24
Qu funciona en la web

25
La Web actual

La Web actual
La web actual
Los objetivos de este captulo son los siguientes:

Comprender el entorno tan cambiante al que nos enfrentamos en el desarrollo web.


Recordar el uso de html y css.
Saber utilizar Chrome Developer Tools.
Acostumbrarse a utilizar Emmet.
Acostumbrarse a utilizar un sistema de control de versiones (GitHub).

26
La Web actual

La Web actual
La web actual
Evolucin de la Web
Como era la web

La web en la actualidad

Accesible desde cualquier dispositivo o entorno

27
La Web actual

La web en el futuro

Siguiendo el principio de universalidad

La web para mviles


Por donde empezar
28
La Web actual

https://developers.google.com/webmasters/mobile-sites/
Curso gratuito Udacity, de Google
Oportunidades de negocio
Google da ms ranking (SEO) para bsquedas desde mviles a las webs con diseo
especfico para mviles (a partir de Abril 2015)
Comprueba si una web est optimizada para mviles

Dos versiones para una sola web?

Es facil que pierdan sincronizacin


No siempre est claro cuando hay que servir la versin mvil y cuando la desktop
Toda la informacin tiene que estar disponible en ambos tipos de webs
Mayor trabajo para el desarrollador
Google defiende el uso de una sola versin para todos los dispositivos

Consideraciones versin movil

Usabilidad
El usuario puede acceder tambin a la versin desktop, especialmente si esta ltima tiene
ms funcionalidad
La redireccin a la versin desktop se debe hacer entra pginas, no al nivel principal de la
web.

SEO

Debemos evitar contenido duplicado

Hay que poner la URL Cannica en los meta.

Desde la versin para PC:

<link rel="alternate" media="only screen and (max-width: 640px)"


href="http://m.example.com/page-1" >

Desde la versin para mviles:

<link rel="canonical" href="http://www.example.com/page-1" >

Un solo diseo antes

Layout fluido:
La web se adaptaba al dispositivo
til al existir pantallas de PC con distintas resoluciones y formatos

29
La Web actual

Un solo diseo ahora

Diseo adaptativo:
Los elementos de la web se adaptan (recolocan) mediante CSS en funcin del tipo de
dispositivo.
Men arriba en vez de lateral
Texto y todos a distinta altura

Diseo responsivo:
Diseo adaptativo y fluido

viewport
Qu es el viewport?

Etiqueta meta introducida por Apple, y luego adoptada y desarrollada ms all por otros.
Se traduce como ventana grfica
Indica al navegador cmo ajustar la pgina web para verse en el terminal:
El terminal "miente" sobre el tamao de su pantalla
Realiza escalado

<meta name="viewport" content="width=980">

Dentro del atributo content se pueden colocar mltiples valores delimitados por comas.

30
La Web actual

Pginas para ordenadores en dispositivos mviles

Cuando no se especifica una ventana grfica en una pgina, los navegadores para mviles
mostrarn esa pgina con un ancho alternativo que ir desde los 800 hasta los 1024 pxeles
CSS.
El factor de escalado de pgina se ajusta de modo que la pgina quepa en la pantalla, lo que
obliga a los usuarios a hacer zoom para interactuar con la pgina.

Necesidad del viewport

Para compatibilidad/usabilidad con los sitios web, los iPhone pedan una ventana grfica de
980px.

Pxeles

Pxel de hardware: pxel fsico en la pantalla:

31
La Web actual

Si miramos la imagen "de cerca" veramos que est compuesta de muchos pxeles:

Est claro que no es lo mismo un monitor de 24'' con resolucin 1920x1080 que la pantalla de un
telfono mvil con 4K. Una imagen que en uno se ve bien, en el otro se vera extremadamente
pequea. Tendremos que trabajar con pxeles lgicos en vez de fsicos en nuestro CSS

Pxel independiente del dispositivo (dip):


Escalado de los pxeles del dispositivo para que coincidan con un pxel de referencia
uniforme a una distancia de visualizacin normal.
El tamao debera ser aproximadamente el mismo en todos los dispositivos.

Pixel CSS:
Unidad utilizada en el diseo de pgina que controla la ventana grfica.
Las dimensiones en pxeles incluidas en estilos como width: 100px se especifican en
pxeles CSS.
La proporcin entre pxeles CSS y pxeles independientes del dispositivo constituye el
factor de escalado de la pgina o el zoom.

window.devicePixelRatio

Los dispositivos aumentan su resolucin (pxeles) pero su device-width y device-height no


cambia
Aumenta su devicePixelRatio
Densidad de pxeles
Nmero aproximado de pxeles fsicos en el dispositivo por cada dip.
La resolucin del dispositivo no es la misma que el viewport del dispositivo
La resolucin ser mayor, es lo que Apple llam Retina Display

Configuracin habitual de nuestro viewport

Hay multitud de dispositivos


Aparecen "bugs" o comportamientos distintos entre los fabricantes
No podemos realizar un viewport especfico para cada dispositivo (targets)
Salvo que funcione bien en todos los dispositivos mviles menos en el de tu jefe :-(
Utilizaremos html5 boilerplate
Opcin custom: http://www.initializr.com/

<meta name="viewport" content="width=device-width, initial-scale=1">

Propiedad initial-scale

<meta name="viewport" content="width=device-width, initial-scale=1">

Valor por defecto 1

Normalmente no la tocaremos

Por qu lo indicamos?

Escenario: Giramos un iOS de modo vertical (portrait) a modo apaisado


Comportamiento: iOS mantiene la anchura que tuviese, y utiliza zoom para llenar la
nueva anchura.

zoom
32
La Web actual

Otras propiedades:
minimum-scale
maximum-scale
user-scalable
Se suelen utilizar tan solo en aplicaciones web embebidas.
Eliminar la posibilidad del zoom limita la accesibilidad.

Media Queries
Hasta CSS3

Utilizamos media types, que siguen siendo tiles


Podemos modificar los estilos de las pginas en funcin del medio donde se visualiza.
Limitacin:
media="handheld" no es suficiente.
Hay demasiados tipos de mviles y tabletas!

Mediante css:

@media print {
body { font-size: 10pt }
}
@media screen {
body { font-size: 13px }
}
@media screen, print {
body { line-height: 1.2 }
}

Mediante html:

<link rel="stylesheet" href="basico.css" media="screen" />


<link rel="stylesheet" media="print" href="especial.css" />
<link rel="stylesheet" media="handheld" href="mobile.css" />

Media Queries

CSS3 introduce las media queries

@media <media-query> {
/* media-specific rules */
}

Pueden utilizar operadores lgicos: not, and, only...

@media screen and (min-width: 1024px){


/*css para pcs*/
}

Lista separada por comas


Actua como un operador OR
Para dispositivos con un ancho desde 700px mviles en apaisado:

@media (min-width: 700px), handheld and (orientation: landscape)


33
La Web actual

{ ... }

Fluid Layout
Unidades de medida

Trabajaremos en ems, rems, porcentajes...


Un diseo fluido soluciona el problema de adaptar nuestra web a distintos tamaos de pantalla
(problemtica anterior a los mviles)
El font-size del navegador es por defecto de 16px

Si queremos trabar en em, una buena opcin es que la conversin de px a ems sea sencilla:

html {font-size: 16px;}


body {
font-size: 62.5%; /*1em = 10px*/
}

Conversin pixels a ems

Lo malo de trabajar con em es que hay que hacer clculos:

<h1>
Ttulo de mi pgina web <a href="#">y enlace a otro sitio</a>
</h1>

h1 {font-size: 30px;
font-weight: bold;}
h1 a {font-size: 14px;}

h1 {font-size: 3em; /* 30px/10px */


font-weight: bold;}

Como sera el css para el font-size del selector h1 a?

h1 a { font-size: 0.46666667em; /* 14px/30px */}

Formula para convertir px a ems

objetivo / contexto = resultado


El objetivo es el elemento en el que queremos cambiar "la medida"
El contexto normalmente ser el elemento container
Para un padding, por ej. el contexto ser el propio elemento (propiedad width)
Para un border en cambio, el contexto ser el elemento container

Inconvenientes de ems

De clculo:

12px (target) / 14px (context) = 0.857142857em (result)

Es facil confundir el context cuando tratas con elementos anidados:


El heading en el main tendr un valor distinto al heading del sidebar si sus containers
tienen diferentes valores em.
34
La Web actual

Hay que definir ms valores y es fcil confundirse.

Unidades rem

root em = rem
El context es siempre el font-size del elemento raz
Los calculos pueden ser ms fciles
Hacemos 1em = 10px
La proporcin anterior nos sirve para cualquier elemento

Unidades relativas al view port

Otra opcin es utilizar una medida relativa al view port (sirve tambin para PC's)

1vw = 1% of viewport width


1vh = 1% of viewport height
1vmin = 1vw or 1vh, whichever is smallest
1vmax = 1vw or 1vh, whichever is largest

Con esta opcin es muy facil crear un botn que ocupe 1/3 de la pantalla:

button { width: 33vmin; height: 33vmin;}

Grids
Normalmente para colocar los elentos en nuestra pgina utilizaremos rejillas o grids

Nos basaremos en grids fluidos:


Todas las columnas de la misma anchura
La anchura ser variable
Testing redimensionando la ventana del navegador.
35
La Web actual

Display flex
Colocar elementos de 1 en 1 mediante filas o columnas flexibles
Ver soporte actual en los navegadores
Bootstrap 4 lo pondr como opcin
Gua para utilizar flexbox

{display: flex;}

Responsive Web Design


Diseo adaptativo

Normalmente un diseo fluido no es suficiente


A menudo habr que plantearse un diseo diferente para distintos dispositivos
Normalmente consideraremos al menos 3 escenarios: mviles, tabletas y PCs.
Generaremos unas hojas de estilo especficas para cada escenario

Mejoraremos la experiencia de usuario:


Evitar lneas de texto excesivamente largas
Guardar proporciones en video en formato 16/9 o en imgenes para modos portrait y
landscape puede condicionar mucho el resto del layout.

Medios para conseguir un diseo adaptativo

Optamos por un sitio web diferente para cada tipo de dispositivo


Agente de usuario
Optamos por un css diferente para cada tipo de dispositivo
Media Queries, a partir de break points o puntos de ruptura

Actualmente es preferible un nico sitio web (diseo adaptativo) que se adapta a los
dispositivos
Mejor para el cliente (SEO)
Mejor para el desarrollador (menos trabajo)
Mejor para Google

Breakpoints

Cambiaremos la disposicin de ciertos elementos html en funcin del dispositivo, resolucin...


Normalmente se hace en funcin de la anchura del viewport.
Hay dispositivos con la misma anchura en pixeles pero distinta densidad de pxeles
Estos puntos de ruptura se definen mediante media queries

Criterio Mobile First

En los dispositivos mviles tenemos menos espacio de pantalla que en un PC


Existe una filosofa Mobile First: centrarse en lo que es verdaderamente importante para el
usuario: en los dispositivos mviles por lo que:
Se simplifica el contenido
Se prioriza el layout
Se optimiza la experiencia de usuario
Diseamos primero para mviles, y luego para el resto.

36
La Web actual

Diseo responsivo

Juntamos un diseo fluido con un diseo adaptativo


Para cada perfil de dispositivos (mviles, tablets, pcs) habr distintas pantallas
Diseo fluido para cada tipo de dispositivo
Nuestro contenido es el que define los breakpoints
Solucin universal
El creador del trmino fue Ethan Marcotte en su artculo Responsive Web Design, ver
traduccin

Imgenes y Video
Consideraciones bsicas de CSS

No deben tener tamao fijo


No queremos que salgan de su elemento contenedor:

img {
max-width: 100%;
}

Tipos de imgenes

Retina Display
Nombre dado por Apple a pantallas con una densidad mayor de lo habitual
Nos harn falta imgenes con una densidad de pxeles mayor (1,5x-2x)
Imgenes mayores (1,5x a 2x) = Tiempos de carga mayores
Habr que cargar este tipo de imgenes tan solo cuando sea necesario
Se suelen nombrar con un sufijo "@2x", antes de la extensin.

Tendremos que distinguir entre:


Imgenes de contenido (mediante la etiqueta img)
Imgenes decorativas (mediante CSS)

Imgenes de contenido

Podemos utilizar el atributo srcset, pero no es una solucin universal


Si el navegador no lo entiende, utilizar el atributo src :-)

<img src="kirkjufell.jpg" srcset="kirkjufell.jpg 1x, kirkjufell@2x.jpg 2x"


alt="Photograph of a blurred waterfall in Iceland">

Otra opcin es utilizar un polyfill

Informacin detallada: http://demosthenes.info/blog/944/Responsive-Images-For-Retina-Using-


HTML5s-srcset

Imgenes decorativas

.box de 200px con una imagen de fondo (200x200):

.box{
background:url('images/box-bg.png') no-repeat top left;
37
La Web actual

width:200px;
height:200px
}

Para una pantalla retina:


Utilizaremos otra imagen de tamao mayor (400x400)
Recuerda que la "," actua como operador OR
Background-size para insertar la imagen de 400px en 200px

@media
only screen and (-webkit-min-device-pixel-ratio: 2),
only screen and ( min--moz-device-pixel-ratio: 2),
only screen and ( -o-min-device-pixel-ratio: 2/1),
only screen and ( min-device-pixel-ratio: 2),
only screen and ( min-resolution: 192dpi),
only screen and ( min-resolution: 2dppx) {
.box{
background:url('images/box-bg@2x.png') no-repeat top left;
background-size: 200px 200px;
}
}

Debug desde el movil


Configuracin del movil

La configuracin siguiente puede cambiar en funcin del dispositivo :-(


Activamos el modo desarrollador:
Vamos a ajustes / Informacin del telfono
Pulsamos en nmero de compilacin al menos 7 veces
Aparece un nuevo item en el men de Ajustes, Opciones de Desarrollo
Activamos la opcin Depuracin USB

Uso de las dev tools

Necesitamos una versin actual de Chrome tanto en el PC como en el movil


Abre la url para depurar en el navegador Chrome de tu movil
Abre la url chrome://inspect en el PC
Conectamos mediante cable USB un movil Android al PC
Aceptamos la clave RSA para el debug desde el ordenador (solo har falta una vez, luego ya
tendremos la clave de este PC)
Ya podremos debugear desde la ventana de Chrome del PC

Reverse Port Forwarding

Si queremos hacer un debug de un sitio web colgado en nuestro PC, deberemos hacer un port
forwarding
Habilitaremos un puerto en el movil que se redireccionar al puerto local del servidor web

38
La Web actual

En este caso, desde el navegador mediante http://localhost:9999 conecta al puerto 80 del PC


Cmo ejecutamos nuestro sitio web de forma rpida?
En Python:

python -m SimpleHTTPServer

En node:

sudo npm install http-server -g


http-server

39
Proyecto Web bsica

Proyecto Web bsica


Proyecto Web Bsica
Prctica sobre html y css con responsive design

Antes de empezar
Realiza un fork de mi repositorio , as podr hacer un seguimiento de tu trabajo.

Descarga el proyecto de tu repositorio ya sea mediante git clone o descargando el zip desde GitHub

Requerimientos generales
Realiza un commit por cada cambio o cambios relacionados que realices en el proyecto. Los mensajes
de los commit tienen que ser claros. Cuelga tu desarrollo en un sitio web y proporciona la URL.

Deber haber un mnimo de 5 commits en 3 das distintos.

Modifica el README para que queden solo:

Los requerimientos especficos, indicando si se han cumplido o no. En caso de no cumplirse,


aade las dificultades que has tenido.
La URL del espacio web donde has colgado tu prctica.

Requerimientos especficos
Crea un sitio web con las siguientes caractersticas:
Est compuesto de 3 pginas: index.html, cervezas.html y contacto.html
Las pginas deben seguir el layout que te proporciono.
La pgina inicial tendr las ltimas noticias (fichero noticias.txt)
La segunda pgina tendr un listado de tus cervezas preferidas (fichero cervezas.json o
cervezas.txt)
La tercera pgina ser un formulario de contacto para aadir cervezas
Tanto el men como el resto de la pgina debe verse bien en dispositivos mviles con los
siguientes requisitos:
El diseo deber ser mobile first
El contenido se debe colocar apilado en vista mviles
El sitio web debe validarse segn la W3C.
No puedes ayudarte de ningn framework ni js (salvo el js que yo te proporciono para el
men)

Para realizar el men responsivo puedes ayudarte del fichero menu.md que te proporciono.

Pgina de inicio:

40
Proyecto Web bsica

Pgina con listado:

Formulario de contacto:
41
Proyecto Web bsica

Vista movil:

42
Proyecto Web bsica

43
Tiempo de carga

Tiempo de carga
Tiempo de carga de un sitio web
Latencia
Elige un servidor adecuado comprobando la respuesta a comandos como ping o httping.
El tiempo de latencia influye y mucho en el load time de la pgina
Busca un hosting en Europa, no necesariamente Espaa, pero evita "saltar el charco".
Usa ingeniera inversa. Averigua el proveedor de hosting de la competencia
El buscador bing mediante el comando ip: xx.xx.xx.xx da informacin sobre virtual hosting.
Tambin puedes usar webs del tipo domaintools.com (de pago).

El tiempo de carga y la performance de una pgina web es muy importante para la experiencia
de usuario (UX).
Si tu web es lenta, no solo pierdes visitas, sino potenciales clientes.
Buscadores como Google tienen en cuanta la velocidad de carga de las webs para sus ranking
de bsqueda.
Cada milisegundo es importante!

Minimizar los HTTP Request


Se cumple la regla del 80/20 o Principio de Pareto
Segn los estudios realizados por Yahoo! el tiempo de carga de una pgina media depende en
un 80% de la parte del cliente y en un 20% de la parte del servidor. Los navegadores de los
usuarios dedican la mayor parte del tiempo a descargar imgenes, archivos JavaScript, hojas de
estilos CSS y otros recursos externos.
Por este motivo, las mejoras en la parte del cliente generan muchos ms beneficios que las
mejoras en la parte del servidor.

Imgenes

Uso de sprites (y tambin image maps para imgenes contiguas).


Eleccin del tamao adecuado de las imgenes: el html no debe escalar la imagen.
PageSpeed Insights (by Google) directamente da las imgenes optimizadas y tambin
informacin sobre el tamao para escalarla (ojo, habr que correr PageSpeed con UserAgents
diferentes si la web es responsiva).
Podemos usar programas como Shrink OMatic o ImageMagick para generar distintas
versiones de nuestras imgenes.

Haza de la optimizacin de las imgenes un hbito

Uso de atributos: texto alternativo (alt), ttulo de la imagen (title) y width y height.
Elige el formato correcto de las imgenes: JPG para imgenes grandes y llenas de colores. GIF
y PNG para el resto.
Nombres de ficheros de imgenes descriptivos (SEO) y en la medida de lo posible con links (al
usuario le gustan y a google tambin).

Uso de imgenes embebidas:


44
Tiempo de carga

Eliminamos peticiones http


Deben ser imgenes pequeas, puedes ver pros y contras.
Herramientas de codificacin. Ejemplo en cdigo:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAA

div.menu {
background-image: url('elephant.png');
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAA
SuQmCC');
}

Uso de CDN
Es importante la proximidad del servidor web al usuario
Un CDN propio es una solucin cara. Necesitamos clientes globales para que tenga sentido.
Con clientes locales ser importante escoger un servidor web con un buen tiempo de respuesta:
pocos saltos de red, cercano.
Un CDN es sencillo de implementar, pero si nuestra aplicacin tiene escrituras a BBDD, el
diseo de la arquitectura distribuida puede ser muy complejo.

Cabeceras HTTP y cache


Los clientes web almacenan en una cach las pginas que van visitando, sus imagenes, css, etc.

Los servidores web indican el tiempo que tiene que estar almacenado en la cache mediante
alguna de las siguientes cabeceras:

Last Modified
ETag
Expires
Max-Age

Ms informacin sobre cada uno de los mtodos

Configurar apache mediante expires

Uso de gzip
Desde HTTP/1.1 los navegadores pueden indicar en las cabeceras http los formatos de
compresin que soportan:

Accept-Encoding: gzip, deflate

El servidor web lee dicho header y en funcin de su configuracin, mandar comprimida la


pgina web, indicndolo tambin en los http headers:

Content-Encoding: gzip

Normalmente el servidor web utiliza una poltica de comprimir ficheros en un funcin de su


extensin.
Comprimiremos html. Tambin podemos comprimir css, js, xml o json. Las imgenes y pdf's no
se comprimen.

45
Tiempo de carga

La compresin de los ficheros suele ser de un 70%.


Ms informacin](http://betterexplained.com/articles/how-to-optimize-your-site-with-gzip-
compression/)
Cmo configurar Apache para que mande las pginas comprimidas

Colocacin de hojas de estilos en la parte superior


Las pginas web se deben renderizar de forma progresiva: sirven al usuario para darle un
indicador de progreso de carga.

Muchos navegadores no renderizan las pginas hasta que no leen todos los css:

As se evitan las penalizaciones en tiempo de ejecutar varios render


El usuario mientras tanto ve una pgina en blanco.
Mejor no utilizar @import en los CSS porque provocan bloqueos.

Resumiendo... los css siempre en el head y antes de cualquier javascript

Colocacin de scripts en la parte inferior


La especificacin HTTP/1.1 sugiere que los navegadores no deben descargar ms de 2 ficheros
de un mismo host de forma simultnea.
Cuando las descargas son scripts, se hacen de una en una
No siempre se pueden llevar a la parte inferior!

Utilizar JavaScript y CSS externos


Si los CSS o JavaScript se utilizan en varias pginas mejor externos
El html ocupar menos y los otros ficheros estarn cacheados entre pginas de la web y no
consumirn un http request
Es negativo para visitantes de una sola pgina.
El mantenimiento es ms sencillo, as como la reusabilidad del cdigo.

Reducir peticiones DNS


Si utilizamos varios hosts, permitimos descargas simultneas
Si utilizamos varios hosts podemos provocar penalizaciones por bsqueda en dns
Los sistemas operativos y los navegadores realizan caches de dns

Uso de versiones minified de JavaScript y CSS


Obliga a tener dos versiones, desarrollo y produccin
Automatizaremos la generacin de la versin de produccin:
Es lo que se conoce como build o compilacin
Usaremos herramientas tipo gulp o grunt

Verificar la carga de una pgina


Utilizando Chrome developer tools podemos ver lo que tarda en empezar a pintar o la pestaa
de Network
Buena documentacin de Yahoo en su portal Yslow (extensin para Google Chrome)
46
Tiempo de carga

PageSpeed Insights (de Google)


Tests desde distintas localizaciones

47
CSS avanzado

CSS avanzado
CSS
Los objetivos de este captulo son los siguientes:

Comprender las ventajas de un lenguaje de preprocesado (Sass o Less) frente a escribir CSS
directamente.
Aprender a usar y personalizar un framework de frontend como Bootstrap
Montar un entorno de trabajo en el que poder trabajar con nuestros ficheros fuentes y compilar
nuestra versin de produccin.
Comprender la evolucin de CSS hacia los web components.

48
Lenguajes de preprocesado: Sass

Lenguajes de preprocesado: Sass


Sass
Conceptos generales
Limitaciones del CSS

CSS no es un lenguaje de programacin:


No permite herencia
No dispone de variables
Las pginas de estilos se pueden volver complejas

Qu es Sass?

Sass significa Syntactically Awesome Stylesheets


Es un lenguaje de preprocesado
El navegador solo entiende CSS
Si utilizamos cualquier otro lenguaje de estilos habr que compilarlo a CSS

Ficheros

La extensin de los ficheros es .scss (sassy css) y .sass


Nos centraremos en .scss (el ms parecido a css)
Un ficheros .scss puede contener tambin cdigo css

Como escribir Sass

Nos centraremos en escribir cdigo css


Incorporamos tcnicas de Sass cuando nos venga bien
Si utilizamos libreras de terceros:
Preferimos cdigo Sass a CSS:
Se entiende mejor
Es ms fcil de modificar

Sintxis
Comentarios

// este comentario no se ver


// cuando compilemos nuestro fichero sass a css
/* pero este otro s */

Importar ficheros

En css se evita el uso de @import ya que el cdigo es sncrono y provoca bloqueos

En sass da igual porque se va a compilar

49
Lenguajes de preprocesado: Sass

Fichero aplication.scss:

/* Mi hoja de estilos */
// tendr el contenido de todo el css de mi aplicacin
// dividido en varios ficheros scss para tener todo organizado
// No hace falta extensin, se sobreentiende scss
@import "buttons";
@import "labels";
...

Al compilar se generar un nico fichero aplication.css


Incluye el fichero buttons.scss y labels.scss

Partials

El compilador tambin genera los ficheros buttons.css y labels.css


Para evitar que se generen se pueden definir como partials:
Basta con renombrarlos a _buttons.scss y _labels.scss
Solo se compilaran como parte de otro fichero
El import no hace falta tocarlo, @import "buttons puede importar:
buttons.sass
button.scss
_buttons.sass
_button.scss

Selectores anidados

#header {
height: 72px;
background: $header-background-color;
h1 {
color: white;
a {
display: block;
text-decoration: none;
}
}

No se debe abusar del anidado


Complica la reusabilidad del cdigo
Lo mismo que en css con los selectores descendentes

Propiedades anidadas

.btn {
text: {
decoration: underline;
transform: lowercase;
}
}

Selector padre: &

50
Lenguajes de preprocesado: Sass

.btn {
&.btn-large {
width: 100px;
// seleccionamos elementos que tengan class="btn btn-large"
}
}

Muy til para pseudoclases:

a {
text-decoration: none;
&:hover { color: #ccc}
&:active {color: #ddd}
}

Variables

$base-color: rgba(blue, 0.5);


$back-color: red !default;

body {
color: $base-color;
background-color: #back-color;
}

La fuente en el body ser de color azul


El color de los prrafos ser rojo en caso de no haberse definido previamente
El mbito de las variables la definen las llaves
Si no existen, sern variables globales

Otro ejemplo:

/*app.scss*/
$rounded: 5px;
@import "buttons"

/*_buttons.scss*/
$rounded: 3px !default;
.btn {
border-radius: $rounded;
}

Interpolacin

Podemos definir un selector o una propiedad mediante una variable:

$elemento = header;
#{$elemento} {
background-color: red;
}

Mixins

Bloques de cdigo que se pueden reusar


51
Lenguajes de preprocesado: Sass

Pueden aceptar argumentos


Si los argumentos tienen valores por defecto, van al final
Debemos definir el mixin antes de usarlo
Puede generar cdigo duplicado (no es el caso siguiente debido a los parmetros)

@mixin headline($size, $color: red) {


color: $color;
font-size: $size;
}
h1 {
@include headline(12px);
}
article h1 {
@include headline(12px, blue);
}

Extends

Similar a mixins pero no acepta parmetros

Genera menos cdigo duplicado:

.icon {
transition: background-color ease .2s;
margin: 0 .5em;
}

.error-icon {
@extend .icon;
/* error specific styles... */
}

.info-icon {
@extend .icon;
/* info specific styles... */
}

Cdigo CSS generado:

.icon, .error-icon, .info-icon {


transition: background-color ease .2s;
margin: 0 .5em;
}

.error-icon {
/* error specific styles... */
}

.info-icon {
/* info specific styles... */
}

Placeholders

52
Lenguajes de preprocesado: Sass

Y si la clase .icon anterior no la usamos en nuestro css?


Y si el nico uso de la clase .icon es para ser extendida?

Utilizaremos placeholders, se codifican anteponiendo un %

%icon {
transition: background-color ease .2s;
margin: 0 .5em;
}

.error-icon {
@extend %icon;
/* error specific styles... */
}

.info-icon {
@extend %icon;
/* info specific styles... */
}

Genera el siguiente cdigo CSS:

.error-icon, .info-icon {
transition: background-color ease .2s;
margin: 0 .5em;
}

.error-icon {
/* error specific styles... */
}

.info-icon {
/* info specific styles... */
}

Mixins vs extends vs placeholders

El caso anterior se podra hacer con un mixin sin parmetros:

@mixin icon {
transition: background-color ease .2s;
margin: 0 .5em;
}

.error-icon {
@include icon;
/* error specific styles... */
}

.info-icon {
@include icon;
/* info specific styles... */
}

53
Lenguajes de preprocesado: Sass

Funcionalmente es lo mismo que usando un placeholder, pero el CSS tiene cdigo repetido:

.error-icon {
transition: background-color ease .2s;
margin: 0 .5em;
/* error specific styles... */
}

.info-icon {
transition: background-color ease .2s;
margin: 0 .5em;
/* info specific styles... */
}

Funciones y estructuras de control

@function
@if
@else
@else if
@each
@for
@while

Operaciones matemticas

Suma, resta, divisin, multiplicacin, mdulo


Funciones definidas:
round($number)
ceil($number) y floor($number)
abs($number)
min y max
percentage

Funciones de color

Evitan usar programas de imgenes para obtener los cdigos hexadecimales de los colores

.lighten {
color: lighten($color, 20%)
}
.darken {
color: darken($color, 20%)
}

Similar con saturate y desaturate buscando colores ms o menos intensos


Otras funciones:
mix para mezclar colores
grayscale($color) para convertir a gris
Hay muchas ms...

54
Lenguajes de preprocesado: Sass

55
JavaScript

JavaScript
JavaScript
Los objetivos de este captulo son los siguientes:

Entender lo que es un lenguaje orientado a eventos y su interaccin con el navegador


Aprender a debugear JavaScript mediante las Chrome Developer Tools
Entender la ventaja de usar JavaScript o nodejs
Conocer las novedades del ES2005

56
Caractersticas generales

Caractersticas generales
Caractersticas generales de JavaScript

Versiones de JavaScript
ES5:
Desde el 2009.
La entienden todos los navegadores.
ES6 o ES2015:
Finalizada en Julio 2015, despus de 6 aos!
Soporte incompleto por los navegadores (hay que usar un transpiler: Babel)
Gua de ES2015

ES7

Ya no se llamar asi
Se crean propuestas que se van aprobando y aadiendo al lenguaje.
As tenemos stages:
Stage 0 - Strawman
Stage 1 - Proposal
Stage 2 - Draft
Stage 3 - Candidate
Stage 4 - Finished

Ms info: http://www.2ality.com/2015/11/tc39-process.html
57
Caractersticas generales

LLamadas sncronas
Hasta que no acaba una instruccin, no empieza la siguiente
Ver ejemplo
No se ejecuta ms JavaScript, en segn que casos puede parecer que est "colgado"
Normalmente no es problema:
Las instrucciones se ejecutan con rapidez (equipos rpidos)
Pero a veces s:
Llamadas a API
Lectura de disco
....

<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-1.11.3.js"></script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JavaScript es single thread</title>
</head>
<body>
<button>Pulsa aqu </button>
<script>
$('button').click(function () {
var answer = prompt("Cmo te llamas?");
console.log(answer);
});
$('button').click(function () {
console.log("Bienvenido");
});
</script>
</body>
</html>

JavaScript es asncrono
Se pude ejecutar una instruccin antes de que acabe la anterior, Ver ejemplo
Anlisis del ejemplo:
En el event handler hay dos funciones:
La primera es asncrona y no evita que otro cdigo se ejecute en el navegador:
console.log ("Peticin realizada")
O la propia renderizacin en el navegador (css o html)
La segunda es una funcin de callback
No se ejecuta hasta que acaba la funcin asncrona

<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-1.11.3.js"></script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JavaScript: llamadas asncronas</title>

58
Caractersticas generales

</head>
<body>
<button>Pulsa aqu </button>
<script>
$('button').click(function() {
$.get('http://www.media.formandome.es/phonegap/tutorial/futbolistas.php'
console.log("Peticin contestada:", data);
});
console.log ("Peticin realizada");
})
</script>
</body>
</html>

JavaScript es casi Single Thread


Nuestro cdigo se ejecuta en un solo hilo

Evitamos tpicos errores de la programacin multihilo

Dificiles de detectar
Dificiles de replicar

JavaSript realmente no es single thread!

Hay un hilo para la ejecucin de nuestro software


Otro hilo para la gestin interna (avisa de que la llamada asncrona ha terminado)

59
linters

linters
Linters en JavaScript
Herramientas que realizan la lectura del cdigo fuente
Detectan errores/warnings de cdigo
Variables sin usar o no definida, llave sin cerrar...
Detectan fallos de estilo
Comillas dobles en vez de simples, espacios en vez de tabulaciones...

JSLint
JSLint es un analizador online de cdigo javaScript creado por Douglas Crockford
Los criterios evaluados corresponden a los que marc su creador
Demasiado estricto
No es configurable o extensible

JSHint
- Fork de JSLint
- El objetivo de JSHint es no imponer un convenio particular
- La gente utiliza diferentes estilos y convenciones.
- El linter debe adaptarse al desarrollador y no al revs

JSCS
- Solo para verificar el estilo del cdigo
- Tiene muchas reglas. No hace falta defirlas, podemos utilizar un [preset](ht

ESLint
- El ltimo en llegar (2013), recoge lo bueno de los anteriores
- Podemos [fijar nuestras reglas](http://eslint.org/docs/rules/) e incluso lue
- Y adems tiene soporte para ES6 y para JSX (que se usa en React)
- Ser el que usemos :-)

60
jQuery

jQuery
jQuery
Qu es jQuery?
jQuery es una librera de funciones JavaScript: Write less, do more

Su funcionalidad principal es la siguiente:

Seleccin y manipulacin de elementos HTML y CSS


Funciones de eventos en HTML
Efectos y animaciones de JavaScript
Ejecucin de peticiones asncronas (AJAX)
Ofrecer compatibilidad en la programacin en JavaScript con distintos navegadores.

Versiones de jQuery
Existen dos ramas, la 1.x y la 2.x. Se pueden descargar de la web de jQuery

Cules son las diferencias?

La rama 2.x no es compatible con IE 6-8


La rama 2.x es algo ms ligera

Qu rama utilizamos?

En principio se pens que la rama 2.x podra tener mucho menos peso, al quitar dependencias
con navegadores antiguos. Sin embargo, surgieron dependencias con los navegadores de los
mviles y la ganancia en kilobytes no fue significativa, en torno a un 10%.

Por otra parte el porcentaje de usuarios con versiones 6, 7 y 8 de Internet Explorer es muy bajo.

Una vez seleccionada la rama hay que elegir si queremos la versin de desarrollo o la versin de
produccin.

Versin de produccin
El fichero tiene el sufijo min: jquery-2.2.3.min.js
Est comprimida (minified)
Aproximadamente 90KB
Versin de desarrollo
Sin comprimir
Aproximadamente 3 veces ms pesada, en torno a 270KB

Cuando llamar a jQuery


En la parte superior de la pgina (head):

Siempre despus de los estilos


Antes de ser utilizado por cualquier otro script o dependencia
61
jQuery

<script type="text/javascript" src="jquery-1.10.2.min.js"></script>

En la parte inferior de nuestra pgina:

Mejor, porque se optimiza la carga de la pgina


Antes de ser utilizado por cualquier otro script o dependencia

CDN
CDN son las siglas de Content Delivery Network. Son un grupo de servidores repartidos por todo el
mundo en puntos estratgicos y pensados para la distribucin de ficheros.

Cuando contratamos un hosting para alojar un sitio web, es habitual que nos oferten el uso de algn
CDN para colgar principalmente contenido esttico.

Ventajas de usar un CDN

Permite al navegador realizar ms peticiones http en paralelo (distintos dominios)


Posibilita la descarga del contenido desde un servidor ms cercano (menor latencia).

Para las libreras ms conocidas es frecuente que empresas como Google o Microsoft nos ofrezcan sus
CDNs.

CDN para jQuery

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/

<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/

<script type="text/javascript" src="http://code.jquery.com/jquery-1.10.2.m

Si el usuario navegada por varias pgina que utilizan el mismo CDN (mismo src),solo lo descarga una
vez, ya que podr usar la cach del navegador.

Ejecucin del cdigo


Si analizamos la carga de un sitio web mediante Chrome Developer Tools, veremos (pestaa Network
o Timeline), dos rayas verticales azul y roja. La raya azul corresponde a la carga del DOM de la
pgina y la roja al evento de load de la pgina.

El evento load siempre es posterior: una vez cargado todo el DOM puede ser que se deba cargar el
contenido de algn iframe, banner de anuncios, imgenes...

Casi siempre que utilizamos jQuery nos hace falta acceder a algn elemento de nuestra pgina.
Cmo hacemos para asegurarnos de que dicho elemento ya est cargado?

Mediante JavaScript
window.onload = function(){ /*Aqu viene mi cdigo de javascript*/ }

Aunque mi cdigo est situado en el head de la pgina, no se ejecutar mi funcin hasta que se
produzca el evento load de la pgina. Ventajas:

El DOM ya est cargado, no tendremos errores. Desentajas:


62
jQuery

Puede que tarde mucho en ejecutarse nuestro cdigo en JavaScript, por ejemplo si hay
imgenes pesadas o la conexin es lenta.

Actividad

Crea una pgina web con un enlace que muestre un alert con el texto "Hola Mundo" y que "anule" el
enlace.

Solucin

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hola Mundo en javaScript</title>
<script type="text/javascript">
window.onload = function() {
document.getElementById("holamundo").onclick = holaMundo;
}
function holaMundo()
{
alert ("Hola Mundo");
return false;
}
</script>
</head>
<body>
<a id="holamundo" href="http://jquery.com/">jQuery</a>
</body>
</html>

Mediante jQuery

jQuery define un nuevo evento, el evento ready para el documento html. El evento ready se produce
cuando el DOM est cargado, aunque no estn renderizados algunos elementos de la pgina. Ojo al
efectuar acciones sobre imgenes si no estn todava cargadas!

$(document).ready(function(){
// Aqu viene mi cdigo jQuery o JavaScript
});

Actividad

Descarga una versin de jQuery e inserta las siguientes instrucciones de jQuery:

$("a").click(function(event) {
alert("Hola Mundo");
event.preventDefault();
});

Solucin

<!DOCTYPE html>
<html lang="en">
<head>
63
jQuery

<meta charset="utf-8">
<title>Hola Mundo con jquery</title>
<script src="jquery-1.10.2.min.js"></script>
<script>
$(document).ready(function() {
$("a").click(function(event) {
alert("Hola Mundo");
event.preventDefault();
});
});
</script>
</head>
<body>
<a href="http://jquery.com/">jQuery</a>
</body>
</html>

Sintaxis de jQuery
En una expresin de jQuery hay 3 partes:

$: para cargar jQuery


(selector): para seleccionar uno o varios elementos del DOM en base a sintaxis de CSS
.action(): Accin que se ejecuta sobre los elementos seleccionados del DOM

Ejemplos de uso del selector de jQuery

$(this).hide() //oculta el elemento actual


$("p").hide() //oculta todos los elementos de tipo prrafo
$("p.test").hide() //oculta todos los prrafos con class=test
$("#test").hide() //oculta todos los elementos con id=test
$("p") //se seleccionan todos los elementos de tipo prrafo
$("p.intro") //todos los prrafos con class=intro
$("p#demo") //todos los prrafos con id=demo
$("[href]") //todos los elementos con atributo href
$("[href='#']") //todos los elementos con atributo href="#"
$("[href!='#']") //todos los elementos con atributo href diferente de "#"
$("[href$='.jpg']") //todos los elementos con atributo href que acabe en .jpg
$("p").css("background-color","yellow"); //modificamos el background-color de
$("p#intro:first") //El primer prrafo con id="intro"
$("ul li:first") El primer elemento <li> de cada <ul>
$("div#intro .head") //Todos los elementos con class="head" dentro de un <div>

Conflictos con otras libreras

Utilizamos jQuery.noConflict() para evitar conflictos de nombre con otras libreras de


JavaScript que puedan utilizar tambin la variable $.

<!DOCTYPE html>
<html>
<head>
<script src="jquery.js"></script>
<script>
64
jQuery

var jq=jQuery.noConflict();
jq(document).ready(function(){
jq("button").click(function(){
jq("p").hide();
});
});
</script>
</head>
<body>
<p>Esto es un prrafo.</p>
<button>Pulsa aqu</button>
</body>
</html>

65
Efectos en jQuery

Efectos en jQuery
Efectos
Son una forma muy visual para entrar en contacto con dos caractersticas muy importantes en jQuery:

Las funciones de callback


La concatenacin de mtodos

Funciones
Utilizaremos las siguientes funciones:

$(selector).hide(speed,callback)
$(selector).show(speed,callback)
$(selector).toggle(speed,callback)
$(selector).slideDown(speed,callback)
$(selector).slideUp(speed,callback)
$(selector).slideToggle(speed,callback)
$(selector).fadeIn(speed,callback)
$(selector).fadeOut(speed,callback)
$(selector).fadeToggle(speed,callback)
$(selector).fadeTo(speed,opacity,callback)

Para ver todas las opciones de efectos consulta la api de efectos de jquery

Parmetros de las funciones

El primer parmetro nos indica la velocidad y puede tener los valores: slow, fast, normal o
milisegundos.
El segundo parmetro es la funcin que hay que ejecutar en el momento en que se complete la
accin de hide o show.
Los parmetros son opcionales

Funcin animate

Con la funcin animate, podemos hacer efectos ms complejos:


Con valores absolutos o relativos
Si ponemos varios animates seguidos, los ir encolando (no empezar una instruccin
hasta terminar la anterior).

$(selector).animate({
left:'250px',
opacity:'0.5',
height:'150px',
width:'150px'
});

El siguiente ejemplo se ejecutar cuando hagamos clic en el botn:

66
Efectos en jQuery

$("button").click(function(){
$("div").animate({
left:'250px',
height:'+=150px',
width:'+=150px'
});
});

Pararemos una animacin mediante la funcin stop:

$(selector).stop(stopAll,goToEnd);

Funciones de callback
JavaScript es asncrono. Como en otros lenguajes, se ejecutan las instrucciones lnea a lnea. Sin
embargo puede ser que una sentencia no haya terminado su ejecucin y ya haya comenzado la
siguiente:

$("p").hide(1000);
alert("El prrafo se ha escondido AHORA?");

En JavaScript las funciones son ciudadanos de primer orden y se pueden pasar como parmetros. Para
evitar el comportamiento asncrono entre las dos instrucciones anteriores, pasaremos la segunda
instruccin como parmetro de la funcin hide. Para hacer esto tendremos que embeberla en una
funcin:

$("p").hide(1000,function(){
alert("El prrafo se ha escondido AHORA");
});

En el ejemplo anterior estamos pasando como parmetro una funcin annima, pero podramos
haberla definido anteriormente guardndola en una variable:

var alerta = function () {


alert("El prrafo se ha escondido AHORA");
};
$("p").hide(1000, alerta);

Encadenar mtodos
Si tenemos que ejecutar varios mtodos o acciones sobre el mismo elemento, se pueden encadenar, de
modo que el elemento se busque mediante el selector de jQuery una nica vez.

$("#p1").css("color","red").slideUp(2000).slideDown(2000);

Tambin lo podramos haber hecho as (ms legible):

$("#p1").css("color","red")
.slideUp(2000)
.slideDown(2000);

67
Efectos en jQuery

68
html y jQuery

html y jQuery
html y jQuery
Manipulacin del contenido html
Cambia el contenido del elemento/s html seleccionado/s:

$(selector).html(contenido)

Aaden contenido en el elemento HTML seleccionado:

$(selector).append(content)
$(selector).prepend(content)

Aaden contenido despus o antes del elemento HTML seleccionado:

$(selector).after(content)
$(selector).before(content)

Manipulacin de atributos de html


Mtodo attr()

Obtenemos los valores de los atributos de las etiquetas html:

//obtenemos el valor del ttulo del enlace:


$("a").attr("title");

Si hay varios atributos se pueden recorrer mediante el mtodo each():

$("a").each(function(i){
var titulo = $(this).attr("title");
alert("Atributo title del enlace " + i + ": " + titulo);
});

Podemos modificar tambin el valor de los atributos pasando un segundo parmetro:

//modificamos el atributo title:


$("a").attr("title", "Mi nuevo ttulo");

Mtodo prop()

$(elemento).prop("checked", true);

Cundo usar attr() y cuando prop()?


Atributos que se modifican con attr(): class, id, href, label, src, title...
Propiedades que se modifican con prop(): autofocus, checked, async, multiple,
readOnly...

Manipulacin de css
69
html y jQuery

Obtiene la propiedad CSS del primer elemento seleccionado:

//$(selector).css(name)
$(this).css("background-color");

Establece el valor de una propiedad CSS de los elementos seleccionados:

//$(selector).css(name,value)
$("p").css("background-color","yellow");

Establece varias propiedades CSS de los elementos seleccionados:

//$(selector).css({properties})
$("p").css({"background-color":"yellow","font-size":"200%"});

Establece la altura de los elementos seleccionados:

//$(selector).height(value)
$("#div1").height("200px");

Establece la anchura de los elementos seleccionados:

//$(selector).width(value)
$("#div2").width("300px");

Formularios
Funcin val(): para obtener los valores de los elementos o inicializarlos.

/*Inicializamos la caja de texto y luego guardamos su contenido en una var


$("textarea").val("Esto es una caja de texto");
var texto = $("textarea").val();

En caso de inicializar varios valores a la vez (por ejemplo un select mltiple), los pondremos
entre corchetes:

$("select").val(["Pedro", "Juan", "Miguel"]);


</source>

Funcin text(): Obtiene o establece el contenido de los elementos seleccionados.

Es parecida a html(), pero obtendremos solo texto, sin etiquetas:

<!DOCTYPE html>
<html>
<head>
<script src="jquery.js"></script>
<script>
$(document).ready(function(){
$("#btn1").click(function(){
alert("Text: " + $("#test").text());
});
$("#btn2").click(function(){
alert("HTML: " + $("#test").html());
});
70
html y jQuery

});
</script>
</head>
<body>
<p id="test">Texto con <b>negrita</b></p>
<button id="btn1">Ver texto</button>
<button id="btn2">Ver html</button>
</body>
</html>

71
Eventos

Eventos
Eventos
Como funcionan los eventos en jQuery
$(".mienlace").click(function(mievento){
mievento.preventDefault();
alert("Has hecho clic. Como he hecho preventDefault, no te llevar al href"
});

El evento se define sobre todos los objetos seleccionados mediante el selector jQuery
En este caso todos los elementos con class="mienlace"
El tipo de evento lo definimos mediante la funcin click u otra similar.
El evento recibe como parmetro una funcin que ser la manejadora del evento.

La funcin manejadora del evento tiene a su vez un parmetro mievento que nos permite utilizar
las propiedades o mtodos del evento en cuestin.
En este caso utilizaremos el mtodo preventDefault()

Listado de Eventos
Eventos relacionados con el ratn

click()

Sirve para generar un evento cuando se produce un clic en un elemento de la pgina.

dblclick()

Para generar un evento cuando se produce un doble clic sobre un elemento.


Se generarn tambin dos eventos click()

mousedown()
Para generar un evento cuando el usuario hace clic independientemente de si lo suelta o
no.
Sirve tanto para el botn derecho como el izquierdo del ratn.
til para drag&drop

$("#p").mousedown(function (b) {
alert(b.which);
//b puede ser 1, 2 o 3 (botn izquierdo, central o derecho)
});

mouseup()
Para generar un evento cuando el usuario ha hecho clic y luego suelta un botn del ratn.
El evento mouseup se produce slo en el momento de soltar el botn.
mousemove()
Evento que se produce al mover el ratn sobre un elemento de la pgina.

72
Eventos

$("#contendedor").mousemove(function (c) {
$(this).html("El ratn se est moviendo. Las coordenadas son " +
});

mouseover() y mouseout()
Sirve para lo mismo que los eventos mouseover y mouseout de Javascript. Se produce
cuando el ratn est sobre un elemento, pero tiene como particularidad que pueden
producirse varias veces mientras se mueve el ratn sobre el elemento, sin necesidad de
haber salido (por los elementos anidados).

mouseenter() y mouseleave()
Normalmente preferiremos estos eventos respecto a los originales de javascript ya que se
ejecutarn slo una vez.

hover()
Esta funcin en realidad sirve para manejar dos eventos, cuando el ratn entra y sale de
encima de un elemento. Por tanto espera recibir dos funciones en vez de una que se enva
a la mayora de los eventos.
A menudo utilizaremos este evento mejor en vez de mouseenter() y mouseleave().

.hover(function() {
Put in mouse enter function here
}, function() {
Put in mouse leave function here
});
//Ejemplo:
$("#p").hover(function () {
$(this).css("background-color", "blue");
}, function () {
$(this).css("background-color", "white");
});

toggle()
Sirve para indicar dos o ms funciones para ejecutar cuando el usuario realiza clics, con
la particularidad que esas funciones se van alternando a medida que el usuario hace clics.

$("#p").toggle(function () {
$(this).css("background-color", "blue");
}, function () {
$(this).css("background-color", "red");
}, function () {
$(this).css("background-color", "yellow");
});

Eventos relacionados con el teclado


Primero se ejecuta uno o varios eventos keydown(), en funcin de si se mantiene o no la tecla
pulsada. Luego uno o varios eventos keypress() y luego un nico evento keyup().

keydown()
Se produce en el momento que se presiona una tecla del teclado, independientemente de
si se libera la presin o se mantiene.
Funciona con todas las teclas.

73
Eventos

keyup()
Se ejecuta en el momento de liberar una tecla.
Funciona con todas las teclas.
keypress()
Se ejecuta como respuesta a una pulsacin e inmediata liberacin de la tecla.
No se dispara con las teclas ALT, MAYS, CTRL.

Los navegadores almacenan de forma diferente las teclas pulsadas. La propiedad which del
evento nos permitir trabajar sin preocuparnos de ello.

Ejemplo:

<html>
<head>
<script type="text/javascript" src="jquery-1.8.2.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$("#keypress").keyup(function (key) {
alert(key.which);
});
});
</script>
</head>
<body>
<p>Key Up Test: <input type="text" name="keypress" id="keypress" /></p
</body>
</html>

Asociacin de DOM y eventos


Mtodos bind(), live() y delegate()

En la versin de jQuery 1.7 han intentado unificar las APIs de manejo de eventos en los
mtodos on() y off().
Estos mtodos sustituyen a los antiguos bind(), delegate() y live().

Mtodo on()

$(elements).on(events [, selector] [, data], handler);

Las funciones para eventos vistas hasta ahora, como click, son atajos a la funcin on():

// Asignar un manejador de eventos usando click


$("#header a").click(function() {
// manejar el evento
});

// Asignar un manejador de eventos usando on


$("#header a").on("click", function() {
// manejar el evento
});

Estas dos construcciones son equivalentes, pero on() permite hacer muchas ms cosas...

74
Eventos

Permite usar un mismo manejador de eventos para mltiples elementos html suscribiendo el
manejador a un elemento padre. Dado el siguiente cdigo html:

<div id="content">
<a href="#">enlace1</a>
<a href="#">enlace2</a>
<a href="#">enlace2</a>
</div>

Si queremos asignar el mismo manejador de eventos a todos los enlaces, podemos hacerlo de la
siguiente forma:

$("#content").on("click", "a", function() {


// manejar el evento
// $(this) apunta al <a> que ha generado el evento
});

Ventajas:

Slo se crea una nica funcin, independientemente del nmero de enlaces que
tengamos, reduciendo el consumo de recursos.
Es vlido para elementos que no existen todava. Si apareciese un nuevo elemento a
dentro del div, automticamente estaramos manejando su evento click. Esto es
especialmente til cuando generamos html dinmicamente.

Permite definir un mismo manejador de eventos para distintos tipos de eventos

$("p").on("click mouseenter mouseleave", function(e){


if ($(this).css("color")!="rgb(250, 100, 0)")
$(this).css("color", "rgb(250, 100, 0)");
else
$(this).css("color", "rgb(150, 0, 255)");
})

Mtodo off()

Para esta accin, contbamos con varios mtodos como unbind(), die() o undelegate().
De nuevo, el objetivo principal de la nueva instruccin es reemplazarlos a todos de un modo
consistente.
La sintaxis de off() resulta similar a la de on():

$(elements).off( [ events ] [, selector] [, handler] );

Con off(), todos los parmetros son opcionales. Cuando se utiliza en su forma ms simple,
$(elements).off(), se eliminan todos los eventos asociados al conjunto seleccionado.

Ejemplo

El evento click se asocia o se elimina del elemento #theone.


Uso de find para optimizar el cdigo
Uso de click() para mayor legibilidad

<!DOCTYPE html>
<html>
<head>
75
Eventos

<style>
button { margin:5px; }
button#theone { color:red; background:yellow; }
</style>
<script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
<button id="theone">Does nothing...</button>
<button id="bind">Add Click</button>
<button id="unbind">Remove Click</button>
<div style="display:none;">Click!</div>
<script>
function aClick() {
$("div").show().fadeOut("slow");
}
$("#bind").click(function () {
$("body").on("click", "#theone", aClick)
.find("#theone").text("Can Click!");
});
$("#unbind").click(function () {
$("body").off("click", "#theone", aClick)
.find("#theone").text("Does nothing...");
});
</script>
</body>
</html>

76
Ajax

Ajax
Ajax
JSON
JavaScript Object Notation
Se utiliza para almacenar e intercambiar informacin
Ms pequeo que XML y ms rpido y sencillo de analizar (parsear).
Se basa en la sintaxis del propio JavaScript para objetos.

//Objeto JSON:
{ "nombre":"Pepe" , "apellido":"Prez" }

Otros ejemplos:

//Array JSON
{
"estudiantes": [
{ "nombre":"Juan" , "lastName":"Alcocer" },
{ "nombre":"Ana" , "lastName":"Serrano" },
{ "nombre":"Mario" , "lastName":"Gil" }
]
}
//sintxis en JavaScript:
var estudiantes = [
{ "nombre":"Juan" , "lastName":"Alcocer" },
{ "nombre":"Ana" , "lastName":"Serrano" },
{ "nombre":"Mario" , "lastName":"Gil" }
];

Qu es AJAX?
AJAX quiere decir Asynchronous JavaScript and XML.
Sirve para cargar datos en background y mostrarlos en la web sin necesidad de recargar la
pgina, por eso lo de asncrono.
XHR significa XML HTTP REQUEST y es hablar de lo mismo.
Lo podemos ver en el inbox de gmail, en google maps cuando aplicamos el zoom, etc.
jQuery y AJAX:
La implementacin de AJAX es distinta en funcin del navegador.
Facilita la sintaxis para usar AJAX

Cachear AJAX

$.ajaxSetup ({
cache: false
});

Ser til usar cach solamente con contenidos estticos.


Es aconsejable indicarlo porque el comportamiento por defecto puede variar en funcin del
77
Ajax

navegador.
La cach solo funciona mediante GET.

Mtodo load
Es el mtodo ms sencillo. Lo usaremos para cargar cierto contenido por AJAX al DOM de la
pgina actual.

$(selector).load(URL,data,callback);

Ejemplo de uso

Peticin de contenido va ajax al pulsar un enlace:

<html>
<head>
<title>Ajax Simple</title>
<script src="jquery-1.8.2.min.js" type="text/javascript"></script>
<script>
$(document).ready(function(){
$("#enlaceajax").click(function(evento){
evento.preventDefault();
$("#destino").load("contenido-ajax.html");
});
})
</script>
</head>
<body>

<a href="#" id="enlaceajax">Haz clic!</a>


<br>
<div id="destino"></div>

</body>
</html>

Seleccionar datos en peticin AJAX

Podemos aadir un selector jQuery a nuestra URL de peticin AJAX:

$("#div1").load("mipagina.html #p1");

En este caso obtendremos del fichero mipagina.html el elemento identificado con id="p1".

Paso de parmetros

El mtodo load puede llevar parmetros o una funcin de callback:

$(document).ready(function(){
$("#enlaceajax").click(function(evento){
evento.preventDefault();
$("#destino").load("recibe-parametros.php", {nombre: "Pepe", edad: 45}
alert("recibidos los datos por ajax");
});
78
Ajax

});
})

Fichero en php:

Recibido el siguiente dato:


<br/>
Nombre: <?php echo $_POST["nombre"];?>
<br/>
Edad: <?php echo $_POST["edad"];?>

Con mensaje de "carga"

$(document).ready(function(){
$("#enlaceajax").click(function(evento){
evento.preventDefault();
var ajax_load = "<img src='img/load.gif' alt='loading...' />";
var loadUrl = "pagina_lenta.php";
$("#result").html(ajax_load).load(loadUrl);
});
})

Fichero en php:

<?php
sleep(3);
echo ("He tardado 3 segundos en ejecutar esta pgina...");
?>

Uso del callback

$(selector).load(URL,data, callback);

El parmetro opcional de callback especifica la funcin de callback a ejecutar cuando el mtodo


load() se haya completado. Puede tener varios parmetros:
responseTxt - contiene el resultado de la llamada si ha sido un xito
statusTXT - contiene el estado de la llamada
xhr - contiene el objeto XMLHttpRequest

Ejemplo de uso:

$("button").click(function(){
$("#div1").load("demo_test.txt",function(responseTxt,statusTxt,xhr){
if(statusTxt=="success")
alert("External content loaded successfully!");
if(statusTxt=="error")
alert("Error: "+xhr.status+": "+xhr.statusText);
});
});

Otros mtodos
$.getJSON(): Obtiene un fichero JSON de un sitio remoto
$.getScript(): Obtiene un fichero javascript de un sitio remoto
79
Ajax

$.get(): hace peticiones ajax va GET


$.post(): hace peticiones ajax va POST
$.ajax(): De ms bajo nivel. Ser til para controlar errores en las peticiones AJAX o alguna
funcin especfica de AJAX (por ejemplo la cache).

Ajax y Firebug
Podemos hacer un seguimiento de las peticiones Ajax desde la pestaa de Red de Firebug,
opcin XHR (XML HTTP REQUEST):

Si pulsamos en el recuadro del + a la izquierda, podremos ver los parmetros que se envan en
la peticin AJAX. En esta peticin no hay ningn parmetro. El nico que hay es un nmero
aleatorio generado para forzar que la peticin no se sirva de la cach.

En la pestaa de respuesta (response) encontramos lo que devuelve la peticin AJAX:

80
Ajax

En este caso enviamos ms de un parmetro va GET. Para pasar ms de un parmetro:

$("#load_get").click(function(){
$("#result")
.html(ajax_load)
.load(loadUrl, "language=php&version=5");
});

Si pasamos los parmetros como un objeto en vez de como una cadena, se enviarn va POST:

$("#load_post").click(function(){
$("#result")
.html(ajax_load)
.load(loadUrl, {language: "php", version: 5});
});

Mtodo .ajax
Utilizaremos ajax mediante el plugin jQuery de Sublime
Tan solo con escribir ajax dispondremos del snippet de Sublime:

$.ajax({
url: '/path/to/file',
type: 'default GET (Other values: POST)',
dataType: 'default: Intelligent Guess (Other values: xml, json, script, or h
81
Ajax

data: {param1: 'value1'},


})
.done(function() {
console.log("success");
})
.fail(function() {
console.log("error");
})
.always(function() {
console.log("complete");
});

Podemos optar por utilizar promesas si la lectura asncrona del cdigo es complicada

82
Adios jQuery?

Adios jQuery?
Adios jQuery?
Un poco de historia
Hasta hace unos aos haba grandes diferencias entre navegadores:

Accediendo al DOM
Gestionando eventos

Aparecieron libreras para lidiar con este tipo de cosas:

jQuery (2005)
Mootols (2007)
....

Qu ha pasado desde, pongamos el 2010?


Microsoft se ha ido acercando a los estndares desde IE9 (2011)
El uso de navegadores no compatibles ha ido decreciendo.
Hay ms posibilidades desde JavaScript para acceso al DOM.
Frameworks como Angular (desde el 2010) utilizan jqLite, una versin muy reducida de
jQuery

Frameworks tipo React (2013) empiezan a trabajar con DOM Virtual:


Trabajar con el DOM es costoso, mejor trabajar con una versin "ms ligera"
Si se producen cambios en el DOM Virtual se trasladan al DOM real
jQuery trabaja de forma directa con el DOM, as que nos resta eficiencia

Usamos jQuery?
Respuesta rpida: NO, salvo por temas de compatibidad
Respuesta meditada:
Si realizas una web (no una webapp) SI
Dispones de muchos plugins y desarrollos ya hechos
Si realizas una webapp NO, utiliza algn framework de JS, pero analiza:
SEO? Tiempo de carga? Renderizacin en servidor?
Componentes que necesitas?

Selectores en JavaScript
Nos hemos acostumbrado a usar tanto jQuery que ahora toca volver a aprender:
A hacer las cosas con el JavaScript de antes
A utilizar nuevas funcionalidades del JavaScript de ahora
Si es nuestro caso, que venimos de un background con jQuery, merece la pena echar un ojo a
alguna gua.

Selector de clase

83
Adios jQuery?

// jQuery
$('.myClass');

// JavaScript
document.getElementsByClassName('myClass');

Selector de id

// jQuery
$('#myID');

// JavaScript
document.getElementById('myID');

Selector de etiqueta

// jQuery
$('div');

// JavaScript
document.getElementsByTagName('div');

querySelector

// Grab the first .myClass class name


document.querySelector('.myClass');

// Return a NodeList of all instances of .myClass


document.querySelectorAll('.myClass');

// Grab the myID id


document.querySelector('#myID');

// Return a NodeList of all 'div' instances


document.querySelectorAll('div');

// Grab the last list Node of .someList unordered list


document.querySelector('ul.someList li:last-child');

// Grab some data-* attribute


document.querySelectorAll('[data-toggle]');

Eventos en JavaScript
Eventos
/*
* Click
*/
// jQuery
$(elem).on('click', function () {...});

84
Adios jQuery?

// JavaScript
document.querySelector(elem).onclick = function () {...}

Encolar eventos

document.addEventListener('click', function() {
// ...
}, false);

Evento de Dom Ready

Lo soportan la mayora de navegadores

document.addEventListener('DOMContentLoaded', function() {
// DOM ready, run it!
}, false);

85
Node.js

Node.js
Node.js
Los objetivos de este captulo son los siguientes:

Entender el concepto de Node.js y su gestor de paquetes npm


Aprender a crear una librera mediante Node.js
Entender la arquitectura y los beneficios de una API REST
Saber configurar una API utilizando Node.js

86
Introduccin a Node.js

Introduccin a Node.js
JavaScript en servidor

Qu es nodejs
NodeJS es un intrprete de JavaScript que se ejecuta en servidor.
Est basado en el motor de JavaScript que utiliza Google Chrome (V8), escrito en C++

Caractersticas principales
El tener el mismo lenguaje en cliente y servidor

Permite a cualquier persona desarrollar en backend o en frontend


Permite reusar cdigo o incluso mover cdigo de cliente a servidor o al revs

Est orientado a eventos y utiliza un modelo asncrono (propio de JavaScript).

Al contrario que en el navegador, encontramos muchas llamadas asncronas:


Llamadas a APIs
Lectura y escritura de ficheros
Ejecucin de clculos en el servidor
....

Llamadas sncronas en servidor seran fatales:


Bloqueariamos las conexiones al servidor hasta que acabase la instruccin bloqueante!
Al ser asncrono podremos tener muchas sesiones concurrentes

Es monohilo
Utiliza un solo procesador
Si queremos usar toda la potencia de la CPU, tendremos que levantar varias instancias de
node y utilizar un balanceador de carga (por ejemplo con pm2)

87
Introduccin a Node.js

Embedded video: https://www.youtube.com/watch?v=9nPdNyMbpSk

Ver la parte interesante del video: 14:47

Desventajas
Trabajar con cdigo asncrono hace que a veces el cdigo no sea excesivamente legible
Imagina que guardamos un registro de los accesos de los usuarios a nuestra app:

trackUser = function(userId) {
users.findOne({userId: userId}, function(err, user) {
var logIn = {userName: user.name, when: new Date};
logIns.insert(logIn, function(err, done) {
console.log('wrote log-in!');
});
});

Tenemos 3 funciones anidadas en una simple operacin.


Esto es lo que se conoce como callback hell

Evitar el callback en el navegador


Mediante el uso de promesas
Se trata de escribir cdigo asncrono con un estilo sncrono.
Opciones ms actuales:
Generators / Yields (ES6)
Async / Await (ES7)
El soporte de ES6 en node es limitado (--harmony) y tambin en el navegador =>
TRANSPILERS (babel)
Ver comparativa de mtodos asncronos

Hola Mundo en node


Editamos un fichero en JavaScript, holaMundo.js:

console.log ("Hola Mundo");

Lo ejecutamos mediante node holaMundo.js


Si escribimos node sin ms, podemos acceder a la consola de node, un intrprete de JavaScript,
igual que el que tenemos en el navegador

npm
Es el gestor de paquetes de node
Propongo hacer dos prcticas para coger la dinmica del uso de npm y sus libreras y de trabajar
con node:
Crear una librera en node.js
Crear una api rest mediante node.js

88
Introduccin a Node.js

89
Crear una librera en node.js

Crear una librera en node.js


Crear una librera en node.JS
Libreras en node
Suelen ser pequeas
Es un buen ejemplo de ciclo de desarrollo en node.js
Ayuda a tener claro el concepto de paquetes de node

Microlibreras
Ventajas
Poco cdigo, se entiende y modifica con facilidad
Reusable
Fcil hacer tests
Desventajas
Tienes que gestionar muchas dependencias
Control de versiones de todas ellas

Funcionalidad librera
Obtiene una marca de cerveza y sus caractersticas
Obtiene una o varias marcas de cerveza al azar.

Control de versiones
Utilizaremos git como control de versiones
Utilizaremos github como servidor git en la nube para almacenar nuestro repositorio:
Haz login con tu usuario (o crea un usuario nuevo)
Crea un nuevo repositorio en GitHub (lo llamar cervezas)
Sigue las indicaciones de GitHub para crear el repositorio en local y asociarlo al
repositorio remoto (GitHub)

Instalacin de node
Lo ms sencillo es instalar mediante el gestor de paquetes

curl -sL https://deb.nodesource.com/setup_5.x | sudo -E bash -


sudo apt-get install -y nodejs

Comprobamos que est correctamente instalado

node -v
npm -v

npm
90
Crear una librera en node.js

Es el gestor de paquetes de node


Debemos crear un usuario en https://www.npmjs.com/
Podemos buscar los paquetes que nos interese instalar
Podemos publicar nuestra librera :-)

Configuracin de npm
Cuando creemos un nuevo proyecto nos interesa que genere automaticamente datos como
nuestro nombre o email
Ver documentacin para su configuacin o mediante consola (npm --help) :
Mediante npm config --help vemos los comandos de configuracin
Mediante npm config ls -l vemos los parmetros de configuracin

npm set init-author-name pepe


npm set init-author-email pepe@pepe.com
npm set init-author-url http://pepe.com
npm set init-license MIT
npm adduser

Los cambios se guardan en el fichero $HOME/.npmrc


npm adduser genera un authtoken = login automtico al publicar en el registro de npm

Versiones en node
Se utiliza Semantic Versioning

npm set save-exact true

Las versiones tienen el formato MAJOR.MINOR.PATCH

Cambios de versin:

MAJOR: Cambios en compatibilidad de API,


MINOR: Se aade funcionalidad. Se mantiene la compatibilidad.
PATCH: Se solucionan bug. Se mantiene compatibilidad.

Puede obligarnos a cambiar el MAJOR muy a menudo!

Creamos el proyecto
Dentro del directorio cervezas:

npm init

El entry-point lo pondremos en src/index.js, as separaremos nuesto cdigo fuente de los tests.


El resto de parmetros con sus valores por defecto
Ya tenemos nuestro package.json creado!

Listar todas las cervezas:


Editamos nuestro fichero src/index.js

var cervezas = require('./cervezas.json')


91
Crear una librera en node.js

module.exports = {
todas: cervezas
}

Abrimos una consola y comprobamos que funcione nuestra librera:

node
> var cervezas = require('./index.js')
undefined
> cervezas.todas

Ahora queremos obtener una cerveza al azar:


Instalamos el paquete uniqueRandomArray

npm i -S unique-random-array

Configuramos nuestro fuente:

cervezas = require('./cervezas.json')
var uniqueRandomArray = require ('unique-random-array')
module.exports = {
todas: cervezas,
alazar: uniqueRandomArray(cervezas)
}

Comprobamos que funcione. Ojo, alazar es una funcin!

Subimos la librera a github


Necesitamos crear un .gitignore para la carpeta no sincronizar node_modules
Los comandos que habr que hacer luego son:

git status
git add -A
git status
git commit -m "versin inicial"

Ojo que haya cogido los cambios del .gitignore para hacer el push

git push

Comprobamos ahora en github que est todo correcto.

Publicamos en npm
npm publish

Podemos comprobar la informacin que tiene npm de cualquier paquete mediante

npm info <nombre paquete>

Probamos nuestra librera


92
Crear una librera en node.js

Creamos un nuevo proyecto e instalamos nuestra librera


Creamos un index para utilizarla:

var cervezas = require('cervezas')


console.log(cervezas.alazar())
console.log(cervezas.todas)

Ejecutamos nuestro fichero:

node index.js

Versiones en GitHub
Nuestro paquete tiene la versin 1.0.0 en npm
Nuestro paquete no tiene versin en GitHub, lo haremos mediante el uso de etiquetas:

git tag v1.0.0


git push --tags

Comprobamos ahora que aparece en la opcin Releases y que la podemos modificar.


Tambin aparece en el botn de seleccionar branch, pulsando luego en la pestaa de tags.

Modificar librera
Queremos mostrar las cervezas ordenadas por nombre
Utilizaremos la librera lodash (navaja suiza del js) para ello:

var cervezas = require('./cervezas.json');


var uniqueRandomArray = require('unique-random-array');
var _ = require('lodash');
module.exports = {
todas: _.sortBy(cervezas, ['nombre']),
alazar: uniqueRandomArray(cervezas)
}

Ahora tendremos que cambiar la versin a 1.1.0 (semver) en el package.json y publicar el


paquete de nuevo
Tambin aadiremos la tag en GitHub Lo vamos pillando?

Versiones beta
Vamos a aadir una cerveza nueva, pero todava no se est vendiendo.
Aumentamos nuestra versin a 1.2.0-beta.0 (nueva funcionalidad, pero en beta)
Al subirlo a npm:

npm publish --tag beta

Con npm info podremos ver un listado de nuestras versiones (mir las dist-tags)
Para instalar la versin beta:

npm install <nombre paquete>@beta

Tests
93
Crear una librera en node.js

Utilizaremos Mocha y Chai


Las instalaremos como dependencias de desarrollo:

npm i -D mocha chai

Aadimos el comando para test en el package.json (-w para que observe):

"test": "mocha src/index.test.js -w"

Creamos un fichero src/index.test.js con las pruebas

var expect = require('chai').expect;


describe('cervezas', function () {
it('should work!', function (done) {
expect(true).to.be.true;
done();
});
});

Utiliza los paquetes Mocha Snippets y Chai Completions de Sublime Text para completar el
cdigo
Ahora prepararemos una estructura de tests algo ms elaborada:

var expect = require('chai').expect;


var cervezas = require('./index');

describe('cervezas', function () {
describe('todas', function () {
it('Debera ser un array de objetos', function (done) {
// se comprueba que cumpla la condicin de ser array de objetos
done();
});
it('Debera incluir la cerveza Ambar', function (done) {
// se comprueba que incluya la cerveza Ambar
done();
});
});
describe('alazar', function () {
it('Debera mostrar una cerveza de la lista', function (done) {
//
done();
});
});
});

Por ltimo realizamos los tests:

var expect = require('chai').expect;


var cervezas = require('./index');
var _ = require('lodash')

describe('cervezas', function () {
describe('todas', function () {
it('Debera ser un array de objetos', function (done) {

94
Crear una librera en node.js

expect(cervezas.todas).to.satisfy(isArrayOfObjects);
function isArrayOfObjects(array){
return array.every(function(item){
return typeof item === 'object';
});
}
done();
});
it('Debera incluir la cerveza Ambar', function (done) {
expect(cervezas.todas).to.satisfy(contieneAmbar);
function contieneAmbar (array){
return _.some(array, { 'nombre': 'MBAR ESPECIAL' });
}
done();
});

});
describe('alazar', function () {
it('Debera mostrar un elemento de la lista de cervezas', function (do
var cerveza = cervezas.alazar();
expect(cervezas.todas).to.include(cerveza);
done();
});
});
});

Automatizar tareas
Cada vez que desarrollamos una versin de nuestra libera:
Ejecutar los tests
Hay que realizar un commit
Hay que realizar un tag del commig
Push a GitHub
Publicar en npm
...
Vamos a intentar automatizar todo:
Semantic Release para la gestin de versiones
Travis como CI (continuous integration)

Instalacin Semantic Release


Paso previo (en Ubuntu 14.04, si no fallaba la instalacin):

sudo apt-get install libgnome-keyring-dev

Instalacin y configuracin:

sudo npm i -g semantic-release-cli


semantic-release-cli setup

.travis.yml: contiene la configuracin de Travis

Cambios en package.json:
95
Crear una librera en node.js

Incluye un nuevo script (semantic-release)


Quita la versin
Aade la dependencia de desarrollo de Semantic Release

Versiones del software


Utilizamos semantic versioning
Semantic Release se ejecuta a travs de Travis CI
Travis CI se ejecuta al hacer un push (hay que configurarlo desde la web)
Los commit tienen que seguir las reglas del equipo de Angular

Uso de commitizen
commitizen que nos ayudar en la generacin de los mensajes de los commit.

La instalacin, siguiendo su documentacin:

sudo npm install commitizen -g


commitizen init cz-conventional-changelog --save-dev --save-exact

Habr que ejecutar git cz en vez de git commit para que los commits los gestione commitizen

Cambio de versin
Vamos a comprobar nuestro entorno aadiendo una funcionalidad
Si pedimos cervezas.alazar() queremos poder recibir ms de una

Los tests:

it('Debera mostrar varias cervezas de la lista', function (done) {


var misCervezas = cervezas.alazar(3);
expect(misCervezas).to.have.length(3);
misCervezas.forEach(function(cerveza){
expect(cervezas.todas).to.include(cerveza);
});
done();
});

Aadimos la funcionalidad en el src/index.js: ``` var cervezas = require('./cervezas.json'); var


uniqueRandomArray = require('unique-random-array'); var = require('lodash'); var getCerveza
= uniqueRandomArray(cervezas) module.exports = { todas: .sortBy(cervezas, ['nombre']),
alazar: alazar }

function alazar(unidades) { if (unidades===undefined){ return getCerveza(); } else { var misCervezas


= []; for (var i = 0; i<unidades; i++) { misCervezas.push(getCerveza()); } return misCervezas; } }

- Hagamos ahora el git cz & git push y veamos como funciona todo
- Podramos aadir un issue y hacer el fix en este commit escribiendo closes #

## Git Hooks
- Son una manera de ejecutar scripts antes de que ocurra alguna accin
- Sera ideal pasar los tests antes de que se hiciera el commit
96
Crear una librera en node.js

- Los Git Hooks son locales:


- Si alguien hace un clone del repositorio, no tiene los GitHooks
- Instalaremos un paquete de npm para hacer git hooks de forma universal

npm i -D ghooks

- Lo configuraremos en el package.json en base a la [documentacin del paquete

"config": { "ghooks": { "pre-commit": "npm test" } }

## Coverage
- Nos interesa que todo nuestro cdigo se pruebe mediante tests.
- Necesitamos una herramienta que compruebe el cdigo mientras se realizan los

npm i -D instanbul

- Modificaremos el script de tests en el package.json:

istanbul cover -x *.test.js _mocha -- -R spec src/index.test.js

- Instanbul analizar la cobertura de todos los ficheros excepto los de test e


- Si ejecutamos ahora *npm test* nos ofrecer un resumen de la cobertura de nu
- Por ltimo nos crea una carpeta en el proyecto *coverage* donde podemos ver
- Ojo, recordar poner la carpeta coverage en el .gitignore!

## Check coverage
- Podemos tambin evitar los commits si no hay un porcentaje de tests ptimo:

"pre-commit": "npm test && npm run check-coverage"

- Creamos el script check-coverage dentro del package.json:

"check-coverage": "istanbul check-coverage --statements 100 --branches 100 --functions 100 -lines
100"

- Podemos comprobar su ejecucin desde el terminal mediante *npm run check-cov


- Lo podemos aadir tambin en Travis, de modo que no se haga una nueva releas

script:

npm run test


npm run check-coverage ```

Grficas
Utilizaremos la herramienta codecov.io:

npm i -D codecov.io

Crearemos un script que recoge los datos de istanbul:

"report-coverage": "cat ./coverage/lcov.info | codecov"

Lo aadimos en travis de modo que genere un reporte:

97
Crear una librera en node.js

after success:
- npm run report-coverage
- npm run semantic-release

Integrado con github (chrome extension)

Por ltimo podemos aadir etiquetas de muchos servicios: npm, codecov, travis... una fuente
habitual es http://www.shields.io

98
Arquitectura de una API REST

Arquitectura de una API REST


Creacin de una API
Qu es una API
Es una forma de describir la forma en que los programas o los sitios webs intercambian datos.
El formato de intercambio de datos normalmente es JSON o XML.

Para qu necesitamos una API?


Ofrecer datos a aplicaciones que se ejecutan en un movil
Ofrecer datos a otros desarrolladores con un formato ms o menos estndar.
Ofrecer datos a nuestra propia web/aplicacin
Consumir datos de otras aplicaciones o sitios Web

Provedores de APIs
Algunos ejemplos de sitios web que proveen de APIS son:
Twitter: acceso a datos de usuarios, estado
Google: por ejemplo para consumir un mapa de Google
Pero hay muchos ms: Facebook, YouTube, Amazon, foursquare...
Pero todava hay muchos ms: directorio de proveedores de APIs

Qu significa API REST


REST viene de, REpresentational State Transfer
Es un tipo de arquitectura de desarrollo web que se apoya totalmente en el estndar HTTP.
REST se compone de una lista de reglas que se deben cumplir en el diseo de la arquitectura de
una API.
Hablaremos de servicios web restful si cumplen la arquitectura REST.
Restful = adjetivo, Rest = Nombre

Como funciona REST


Llamadas al API

Las llamadas al API se implementan como peticiones HTTP, en las que:

La URL representa el recurso

http://www.formandome.es/api/cursos/1

El mtodo (HTTP Verbs) representa la operacin:

GET http://www.formandome.es/api/cursos/1

El cdigo de estado HTTP representa el resultado:

99
Arquitectura de una API REST

200 OK HTTP/1.1
404 NOT FOUND HTTP/1.1

Creacin de recursos

La URL estar abierta (el recurso todava no existe y por tanto no tiene id)
El mtodo debe ser POST

http://eventos.com/api/eventos/3/comentarios

Respuesta a la creacin de recursos

Resultados posibles:
403 (Acceso prohibido)
400 (peticin incorrecta, p.ej. falta un campo o su valor no es vlido)
500 (Error del lado del servidor al intentar crear el recurso, p.ej. se ha cado la BD)
201 (Recurso creado correctamente)
Qu URL tiene el recurso recin creado?
La convencin en REST es devolverla en la respuesta como valor de la cabecera HTTP
Location

Actualizacin de recursos

Mtodo PUT
Segn la ortodoxia REST, actualizar significara cambiar TODOS los datos
PATCH es un nuevo mtodo estndar HTTP (2010) pensado para cambiar solo ciertos
datos. Muchos frameworks de programacin REST todava no lo soportan
Resultados posibles
Errores ya vistos con POST
201 (Recurso creado, cuando le pasamos el id deseado al servidor)
200 (Recurso modificado correctamente)

Eliminar recursos

Mtodo DELETE
Algunos resultados posibles:
200 OK
404 Not found
500 Server error
Tras ejecutar el DELETE con xito, las siguientes peticiones GET a la URL del recurso
deberan devolver 404

Arquitectura REST
Reglas de una arquitectura REST

Interfaz uniforme
Peticiones sin estado
Cacheable
Separacin de cliente y servidor
Sistema de Capas
Cdigo bajo demanda (opcional)

100
Arquitectura de una API REST

Interfaz Uniforme

La interfaz de basa en recursos (por ejemplo el recurso Empleado (Id, Nombre, Apellido,
Puesto, Sueldo)
El servidor mandar los datos (va html, json, xml...) pero lo que tenga en su interior (BBDD
por ejemplo) para el cliente es transparente
La representacin del recurso que le llega al cliente, ser suficiente para poder cambiar/borrar el
recurso:
Suponiendo que tenga permisos
Por eso en el recurso solicitado se suele enviar un parmetro Id

Interfaz uniforme: mensajes descriptivos

Mensajes descriptivos:
Usar las caractersticas del protocolo http para mejorar la semntica:
HTTP Verbs
HTTP Status Codes
HTTP Authentication
Procurar una API sencilla y jerrquica y con ciertas reglas: uso de nombres en plural

Peticiones sin estado

http es un protocolo sin estado ---> mayor rendimiento

GET mi_url/empleados/1234
DELETE mi_url/empleados/1234

En la segunda peticin hemos tenido que incidar el identificador del recurso que queremos
borrar
El servidor no guardaba los datos de la consulta previa que tena el cliente en partcular.
Una peticin del tipo DELETE mi_url/empleado debe dar error, falta el id y el servidor no lo
conoce!

Cacheable

En la web los clientes pueden cachear las respuestas del servidor


Las respuestas se deben marcar de forma implcita o explcita como cacheables o no.
En futuras peticiones, el cliente sabr si puede reutilizar o no los datos que ya ha obtenido.
Si ahorramos peticiones, mejoraremos la escabilidad de la aplicacin y el rendimiento en
cliente (evitamos principalmente la latencia).

Separacin de cliente y servidor

El cliente y servidor estn separados, su unin es mediante la interfaz uniforme


Los desarrollos en frontend y backend se hacen por separado, teniendo en cuenta la API.
Mientras la interfaz no cambie, podremos cambiar el cliente o el servidor sin problemas.

Sistema de capas

El cliente puede estar conectado mediante la interfaz al servidor o a un intermediario, para el es


irrelevante y desconocido.
Al cliente solo le preocupa que la API REST funcione como debe: no importa el COMO sino el
QUE
101
Arquitectura de una API REST

El uso de capas o servidores intermedios puede servir para aumentar la escalabilidad (sistemas
de balanceo de carga, cachs) o para implementar polticas de seguridad

Cdigo bajo demanda (opcional)

Los servidores pueden ser capaces de aumentar o definir cierta funcionalidad en el cliente
transfirindole cierta lgica que pueda ejecutar:
Componentes compilados como applets de Java
JavaScript en cliente.

Consejos para elaborar una API REST


Versiones del API

Los cambios en el cdigo no deberan afectar al API


Si hay cambios en el API se deben usar versiones para no fustrar a los desarrolladores
La mejor opcin es aadir un prefijo a las URLS:

GET /v1/geocode HTTP/1.1


Host: api.geocod.io

GET /v2/geocode HTTP/1.1


Host: api.geocod.io

HTTP verbs

Si realizamos CRUD, debemos utilizar los HTTP verbs de forma adecuada para cuidar la
semntica.
GET: Obtener datos. Ej: GET /v1/empleados/1234
PUT: Actualizar datos. Ej: PUT /v1/empleados/1234
POST: Crear un nuevo recurso. Ej: POST /v1/empleados
DELETE: Borrar el recurso. Ej: DELETE /v1/empleados/1234
PATCH?: Para actualizar ciertos datos

Nombre de los recursos

Plural mejor que singular, para lograr uniformidad:


Obtenemos un listado de clientes: GET /v1/clientes
Obtenemos un cliente en partcular: GET /v1/clientes/1234
Url's lo ms cortas posibles
Evita guiones y guiones bajos
Deben ser semnticas para el cliente
Utiliza nombres y no verbos
Estructura jerrquica para indicar la estructura: /v1/clientes/1234/pedidos/203

Cdigos de estado

Se utilizan los cdigos de estado de http


Si realizamos un request de POST deberemos devolver un 201.
Se pueden producir mltiples errores en la llamada al API:
falta de permisos
errores de validacin
O incluso un error interno de servidor.
102
Arquitectura de una API REST

Siempre se debe devolver un cdigo de estado HTTP con los requests.


Aadir un mensaje de error si es necesario.

Formato de salida

En funcin de la peticin nuestra API podra devolver uno u otro formato.


Nos fijaremos en el ACCEPT HEADER

GET /v1/geocode HTTP/1.1


Host: api.geocod.io
Accept: application/json

*GET /v1/geocode HTTP/1.1


Host: api.geocod.io
Accept: application/xml

En principio utilizaremos JSON: sencillo y simple


XML no es nuestro amigo: schemas, namespaces...
Si no es un requerimiento, evitaremos XML

Solicitudes AJAX entre dominios


Problemtica

El modelo de seguridad de las aplicaciones web no permite en principio realizar peticiones


Ajax entre dominios
En general esto es OK, a nadie le gustara que cdigo malicioso de una URL estuviera
accediendo a ningn dato de la solapa del navegador que est abierta con nuestra cuenta
bancaria

Pero tambin es un problema, por ejemplo con AJAX: una pgina de http://localhost en
principio no puede hacer una peticin AJAX a Google
Como consecuencia, se han tenido que idear diversos trucos/tcnicas para intentar sobrepasar
este lmite

Tcnicas para evitar las restricciones de seguridad

Lo ms habitual es el uso de JSONP (JSON con Padding)


Se basa en que aunque no podemos consumir datos de otro dominio va XHR, si podemos
cargar un script de dicho dominio

CORS

En el 2008 se public la primera versin de la especificacin XMLHttpRequest Level 2.


CORS es el acrnimo de Cross-origin resource sharing.
Debemos tener presente, que los navegadores antiguos no soportan CORS.
Esta nueva especificacin, aade funcionalidades nuevas a las peticiones AJAX como las
peticiones entre dominios (cross-site), eventos de progreso y envio de datos binarios.
CORS requiere configuraciones en el servidor.

Autenticacin y validacin en API REST

103
Arquitectura de una API REST

Mtodos de autenticacin

Bsicamente tenemos dos formas de implementar la autenticacin en servidor:


Basada en cookies, la ms utilizada:
El servidor guarda la cookie para autenticar al usuario en cada request.
Habr que tener un almacen de sesiones: en bbdd, Redis...

- **Basada en tokens**, se confa en un token firmado que se enva al servidor

Qu es un token?

Un token es un valor que nos autentica en el servidor

Normalmente se consigue despus de hacer login mediante usuario/contrasea

Cmo se genera el token?

Normalmente un hash calculado con algn dato (p.ej. login del usuario + clave secreta)
Adems el token puede llevar datos adicionales como el login

Cmo comprueba el servidor que es vlido?


Generando de nuevo el Hash y comprobando si es igual que el que enva el usuario
(100% stateless)
O bien habiendo almacenado el Hash en una B.D. asociado al usuario y simplemente
comprobando que coincide

Beneficios de usar tokens

Uso entre dominios


cookies + CORS no se llevan bien

OAuth

104
Arquitectura de una API REST

Para que una app pueda acceder a servicios de terceros sin que el usuario tenga que darle a la
app sus credenciales del servicio
Ejemplo: una app que permite publicar en tu muro de FB, pero en la que no confas lo
suficiente como para meter tu login y password de FB
Es el estndar en APIs REST abiertos a terceros
Se basa en el uso de un token de sesin

Terminologa de OAuth

En un proceso AUTH intervienen 3 actores:


Consumer: El servicio al que el usuario quiere acceder usando una cuenta externa.
Service Provider: Al servicio de autenticacin externo se le llama Service Provider.
El usuario final

Flujo en OAuth

El consumer pide un token al service provider, esto es transparente para el usuario.


El consumer redirige al usuario a una pgina segura en el service provider, pasndole el token
como parmetro.
El usuario se autentica en la pgina del service provider, validando el token.
El service provider enva al usuario de vuelta a la pgina del consumer especificada en el
parmetro oauth_callback.
El consumer recoge al usuario en la callback URL junto con el token de confirmacin de
identidad.

105
Creacin de una API con node.js

Creacin de una API con node.js


Creacin de una API con node.js
Primeros pasos
npm configurado y git configurado
Crear repositorio en GitHub
Clonar repositorio
Ejecutar npm init
Crear la estructura de la aplicacin, por el momento una carpeta app donde iremos guardando el
cdigo propio de la aplicacin

Configuracin de eslint
Si tienes los linters para Sublime y js configurados, comprueba que la consola arroja un error.

Hay que configurar eslint para formatear nuestro cdigo.

npm i -D eslint

Como lo instalo en local, para ejecutarlo, necesito darle el path:

./node_modules/.bin/eslint --init
? How would you like to configure ESLint? Answer questions about your styl
? Are you using ECMAScript 6 features? No
? Where will your code run? Node
? Do you use JSX? No
? What style of indentation do you use? Spaces
? What quotes do you use for strings? Single
? What line endings do you use? Unix
? Do you require semicolons? No
? What format do you want your config file to be in? JSON
Successfully created .eslintrc.json file in /home/juanda/api_node_express/

Comprueba que el linter de JavaScript te funcione bien

express
Utilizaremos express para realizar la API
Instalar express mediante uno de los comandos siguientes:

npm install --save express


npm i -S express

Creamos el fichero app/server.js donde pondremos el cdigo necesario para testear una API
muy bsica para probar Express.

Utiliza el plugin ExpressComplete (aget, aput...) de Sublime para autocompletado

106
Creacin de una API con node.js

var express = require('express') //llamamos a Express


var app = express()

var port = process.env.PORT || 8080 // establecemos nuestro puerto

app.get('/', function(req, res) {


res.json({ mensaje: 'Hola Mundo!' })
})

app.get('/cervezas', function(req, res) {


res.json({ mensaje: 'A beber cerveza!' })
})

app.post('/', function(req, res) {


res.json({ mensaje: 'Mtodo post' })
})

app.del('/', function(req, res) {


res.json({ mensaje: 'Mtodo delete' })
})

// iniciamos nuestro servidor


app.listen(port)
console.log('API escuchando en el puerto ' + port)

Si el linter de js te da un error por usar console.log, puedes deshabilitar esa regla en el fichero
de configuracin de eslint

no-console: 0

Iniciar y testear a mano nuestra API

Iniciamos nuestro API Server mediante el comando

node app/server.js

Probamos que la API funcione mediante http://localhost:8080 o utilizando la extensin de


Google Chrome Postman

Creamos una entrada en nuestro fichero package.json, de modo que podamos arrancar nuestra
API mediante npm start

"start": "node app/server.js"

Hagamos un commit del repositorio, pero sin tener en cuenta la carpeta node_modules.
Comprueba con el segundo git status que git no lo tiene en cuenta antes de continuar con el
commit:

git status
echo "node_modules">.gitignore
git status
git add -A *
git commit -m "Primera versin API"
git push
107
Creacin de una API con node.js

Debemos hacer nuevas instantneas en pasos posteriores, pero ya no las documentar por
brevedad.

nodemon
Es un wrapper de node, para reiniciar nuestro API Server cada vez que detecte modificaciones.

npm i -D nodemon

Cada vez que ejecutemos npm start ejecutaremos nodemon en vez de node. Habr que cambiar
el script en el fichero package.json:

"start": "nodemon app/server.js"

Uso de enrutadores
Imagina que nuestra API es compleja:

Tiene varios recursos (GET, POST... por cada uno de ellos)


Versionado de la API

Utilizaremos enrutadores

Asociamos enrutadores a la app en vez de rutas directamente


Cada enrutador se puede asociar por ejemplo a un recurso
Se pueden anidar enrutadores

El cdigo para un enrutador sera as:

// para establecer las distintas rutas, necesitamos instanciar el express


var router = express.Router()

//establecemos nuestra primera ruta, mediante get.


router.get('/', function(req, res) {
res.json({ mensaje: 'Bienvenido a nuestra API!' })
})

// nuestra ruta ir en http://localhost:8080/api


// es bueno que haya un prefijo, sobre todo por el tema de versiones de la
app.use('/api', router)

Recibir parmetros
Cuando el router recibe una peticin, podemos observar que ejecuta una funcin de callback:

function (req, res){}

El parmetro req representa la peticin (request)


El parmetro res representa la respuesta (response)
En el caso anterior hemos codificado la respuesta en json:

res.json({ mensaje: 'Bienvenido a nuestra API!' })

A menudo la peticin se har enviando algn parmetro adicional. Hay varias posibilidades:
108
Creacin de una API con node.js

Mediante la url: se recogern mediante

req.param.nombreVariable

Mediante post en http hay dos posiblidades:


application/x-www-form-urlencoded
multipart/form-data
En peticiones post, escogeremos x-www-form-urlencoded si no se enva una gran cantidad de
datos (normalmente ficheros)

Parmetros por url


Vamos a mandar un parmetro nombre a nuestra api, de modo que nos de un saludo
personalizado.

router.get('/:nombre', function(req, res) {


res.json({ mensaje: 'Hola' + req.params.nombre })
})

Parmetros por post


Parmetros mediante POST y application/x-www-form-urlencoded:
Necesitaremos body-parser: extrae los datos del body y los convierte en json
Parmetros mediante POST y multipart/form-data
Usaremos https://www.npmjs.com/package/busboy o Multer

Ejemplo con body-parser


Hay que instalar body-parser

npm i -S body-parser

body-parser acta como middleware

El cdigo adicional ser similar al siguiente:

var bodyParser = require('body-parser')


app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json())

router.post('/',function(req,res) {
res.json({mensaje: req.body.nombre})
})

Rutas de nuestra API


Las rutas que utilizaremos son las siguientes:

Ruta Verbo http Descripcin


/api/cervezas GET Obtenemos todas las cervezas
/api/cervezas/search?q=keyword GET Obtenemos cervezas por keyword
/api/cervezas/:id GET Obtenemos los datos de una cerveza
109
Creacin de una API con node.js

/api/cervezas POST Damos de alta una cerveza


/api/cervezas/:id PUT Actualizamos los datos de una cerveza
/api/cervezas/:id DELETE Borramos los datos de una cerveza

Como la configuracin se complica, lo suyo es dividirla:


Creamos una carpeta app/routes donde irn las rutas
Creamos un fichero app/routes/index.js donde ir el enrutador del versionado de la
API
Creamos un fichero en app/routes por cada resouce (en este caso solo uno,
cervezas.js)

El fichero app.js queda as:

var express = require('express') //llamamos a Express


var app = express()
var bodyParser = require('body-parser')

var port = process.env.PORT || 8080 // establecemos nuestro puerto

app.use(bodyParser.urlencoded({ extended: true }))


app.use(bodyParser.json())

// nuestra ruta ir en http://localhost:8080/api


// es bueno que haya un prefijo, sobre todo por el tema de versiones de la
var router = require('./routes')
app.use('/api', router)

//arrancamos el servidor
app.listen(port)
console.log('API escuchando en el puerto ' + port)

El fichero app/routes/index.js

var router = require('express').Router()


var cervezas = require('./cervezas')

router.use('/cervezas', cervezas)

router.get('/', function (req, res) {


res.status(200).json({ message: 'Ests conectado a nuestra API' })
})

module.exports = router

Y el fichero app/routes/cervezas.js:

var router = require('express').Router()


router.get('/search', function(req, res) {
res.json({ message: 'Vas a buscar una cerveza' })
})
router.get('/', function(req, res) {
res.json({ message: 'Ests conectado a la API. Recurso: cervezas' })
})

110
Creacin de una API con node.js

router.get('/:id', function(req, res) {


res.json({ message: 'Vas a obtener la cerveza con id ' + req.params.id })
})
router.post('/', function(req, res) {
res.json({ message: 'Vas a aadir una cerveza' })
})
router.put('/:id', function(req, res) {
res.json({ message: 'Vas a actualizar la cerveza con id ' + req.params.id
})
router.delete('/:id', function(req, res) {
res.json({ message: 'Vas a borrar la cerveza con id ' + req.params.id})
})
module.exports = router

Acceso a base de datos


Para la persistencia de nuestros datos utilizaremos una base de datos
Optamos por una base de datos MongoDB:
Es lo ms habitual en arquitecturas MEAN
As operamos con objetos json tanto en node como en bbdd (bson)
Nos permite ms libertad, al utilizar colecciones en vez de tablas

Instalacin de MongoDB
Instalamos y leventamos el servicio de MongoDB:

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv EA312927


echo "deb http://repo.mongodb.org/apt/ubuntu trusty/mongodb-org/3.2 multiv
sudo apt-get update
sudo apt-get install -y mongodb-org

El servicio se levanta como otros servicios de Linux:

sudo service mongod start

Y para entrar a su consola, mediante mongo, o mediante algn gui como por ejemplo
Robomongo

La consola de Mongo tambin es un intrprete de JavaScript :-)

Insercin de datos
Utilizaremos el fichero cervezas.json, lo podemos obtener mediante:

wget https://raw.githubusercontent.com/juanda99/proyecto_web_basica/master

Importar nuestro cervezas.json a una base de datos

mongoimport --db web --collection cervezas --drop --file cervezas.json --j

Para poder hacer una bsqueda por varios campos de texto, tendremos que hacer un ndice:

$ mongo # para entrar en la consola de mongo

111
Creacin de una API con node.js

use web; #seleccionamos la bbdd


db.cervezas.createIndex(
{
"Nombre": "text",
"Descripcin": "text"
},
{
name: "CervezasIndex",
default_language: "spanish"
}
)

Comprobamos que el ndice est bien creado

db.cervezas.getIndexes()

Si hiciera falta, lo podemos recrear:

db.cervezas.dropIndex("CervezasIndex")

Instalacin de Mongoose
Instalaremos [mongoose] como ODM (Object Document Mapper) en vez de trabajar con el
driver nativo de MongoDB (se utiliza por debajo).

npm i -S mongoose

Uso de Mongoose
Creamos el fichero app/db.js donde configuraremos nuestra conexin a base de datos mediante
mongoose:

//incluimos Mongoose y abrimos una conexin


var mongoose = require('mongoose')
var MONGO_URL = process.env.MONGO_URL || 'mongodb://localhost/web'
mongoose.connect(MONGO_URL)

mongoose.connection.on('connected', function () {
console.log('Conectado a la base de datos: ' + MONGO_URL)
})

mongoose.connection.on('error',function (err) {
console.log('Error al conextar a la base de datos: ' + err)
})

mongoose.connection.on('disconnected', function () {
console.log('Desconectado de la base de datos')
})

process.on('SIGINT', function() {
mongoose.connection.close(function () {
console.log('Desconectado de la base de datos al terminar la app')
process.exit(0)
112
Creacin de una API con node.js

})
})

En nuestro fichero app/server.js incluimos el fichero de configuracin de bbdd:

var express = require('express') //llamamos a Express


var bodyParser = require('body-parser')
/*toda la configuracin de bbdd la hacemos en un fichero a parte*/
require('./db')
....

Modelos
Definimos un esquema para nuestros objetos (cervezas) y creamos nuestro modelo a partir del
esquema (fichero app/models/Cervezas.js):

var mongoose = require('mongoose')


var Schema = mongoose.Schema

var cervezaSchema = new Schema({


Nombre: String,
Descripcin: String,
Graduacion: String,
Envase: String,
Precio: String
})

var Cerveza = mongoose.model('Cerveza', cervezaSchema)

module.exports = Cerveza

Ahora podramos crear documentos y guardarlos en la base de datos:

var miCerveza = new Cerveza({ name: 'Ambar' });


miCerveza.save(function (err, miCerveza) {
if (err) return console.error(err);
console.log('Guardada en bbdd' + miCerveza.name);
})

Uso de controladores
Desde nuestro fichero de rutas (app/routes/cervezas.js), llamaremos a un controlador que ser el
encargado de aadir, borrar o modificar cervezas en base al modelo anterior.
Nuestro cdigo queda as perfectamente separado y cada fichero de rutas se encargar solo de
gestionar los endpoints de nuestra API para el recurso en cuestin.

Creamos un directorio especfico para los controladores, donde colocaremos el especfico para
las cervezas.
Nuestro cdigo quedas as (fichero app/controllers/cervezasController.js):

var Cervezas = require('../models/Cervezas')


module.exports = {
// https://docs.mongodb.com/v3.0/reference/operator/query/text/

113
Creacin de una API con node.js

search: function (req, res) {


var q = req.query.q
Cervezas.find({ $text: { $search: q } }, function(err, cervezas) {
if(err) {
return res.status(500).json({
message: 'Error en la bsqueda'
})
}
return res.json(cervezas)
})
},
list: function(req, res) {
Cervezas.find(function(err, cervezas){
if(err) {
return res.status(500).json({
message: 'Error obteniendo la cerveza'
})
}
return res.json(cervezas)
})
},
show: function(req, res) {
var id = req.params.id
Cervezas.findOne({_id: id}, function(err, cerveza){
if(err) {
return res.status(500).json({
message: 'Se ha producido un error al obtener la cerveza'
})
}
if(!cerveza) {
return res.status(404).json( {
message: 'No tenemos esta cerveza'
})
}
return res.json(cerveza)
})
},
create: function(req, res) {
var cerveza = new Cervezas (req.body)
cerveza.save(function(err, cerveza){
if(err) {
return res.status(500).json( {
message: 'Error al guardar la cerveza',
error: err
})
}
return res.status(201).json({
message: 'saved',
_id: cerveza._id
})
})
},
update: function(req, res) {
114
Creacin de una API con node.js

var id = req.params.id
Cervezas.findOne({_id: id}, function(err, cerveza){
if(err) {
return res.status(500).json({
message: 'Se ha producido un error al guardar la cerveza',
error: err
})
}
if(!cerveza) {
return res.status(404).json({
message: 'No hemos encontrado la cerveza'
})
}
cerveza.Nombre = req.body.nombre
cerveza.Descripcin = req.body.descripcion
cerveza.Graduacion = req.body.graduacion
cerveza.Envase = req.body.envase
cerveza.Precio = req.body.precio
cerveza.save(function(err, cerveza){
if(err) {
return res.status(500).json({
message: 'Error al guardar la cerveza'
})
}
if(!cerveza) {
return res.status(404).json({
message: 'No hemos encontrado la cerveza'
})
}
return res.json(cerveza)
})
})
},
remove: function(req, res) {
var id = req.params.id
Cervezas.findByIdAndRemove(id, function(err, cerveza){
if(err) {
return res.json(500, {
message: 'No hemos encontrado la cerveza'
})
}
return res.json(cerveza)
})
}
}

El router que gestiona el recurso se encarga de llamarlo (fichero app/routes/cervezas.js):

var router = require('express').Router()


var cervezasController = require ('../controllers/cervezasController')

router.get('/search', function(req, res) {


cervezasController.search(req, res)

115
Creacin de una API con node.js

})
router.get('/', function(req, res) {
cervezasController.list(req, res)
})
router.get('/:id', function(req, res) {
cervezasController.show(req, res)
})
router.post('/', function(req, res) {
cervezasController.create(req, res)
})
router.put('/:id', function(req, res) {
cervezasController.update(req, res)
})
router.delete('/:id', function(req, res) {
cervezasController.remove(req, res)
})
module.exports = router

Test desde el navegador o mediante Postman

Comprobamos que se genera el listado de cervezas


Comprobamos que se busca por keyword:

http://localhost:8080/api/cervezas/search?q=regaliz

...

Test de la API
Utilizaremos Mocha como test framework y supertest para hacer las peticiones http.

npm i -D mocha supertest

Creamos nuestro fichero tests/api.test.js con la prueba para crear una cerveza:

'use strict'
/* global describe it */
var request = require('supertest')

/*obtenemos nuestra api rest que vamos a testear*/


var app = require('../app/server')

describe('Crear una nueva cerveza', function() {


it('Crea la cerveza retornando 201', function(done) {
request(app)
.post('/api/cervezas/')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.send({
'Nombre': 'DAMN',
'Descripcin': 'Mi cerveza preferida',
'Graduacin': '10',
'Envase': 'Bidn',

116
Creacin de una API con node.js

'Precio': '1 eurito'


})
.expect(201, done)
})
})

Utiliza los paquetes Mocha Snippets y Chai Completions de Sublime Text para completar el
cdigo

Si echamos un vistazo al cdigo anterior:

describe nos sirve para describir los test suites (se pueden anidar varios)
it nos sirve para describir cada caso de test.
requests(app).post realizar una peticin post a nuestra api

Cmo ejecutamos el test?

Mediante lnea de comandos (hace falta la ruta completa ya que no hemos instalado el
paquete de forma global):

node_modules/.bin/mocha tests

Introduciendolo en el fichero package.json (no hace falta la ruta al estar dentro del
package.json):

"test": "mocha tests"

Para que el caso anterior funcione, tenemos que modificar nuestro fichero app/server de modo
que se pueda utilizar app desde otro fichero js:

/*lo aado al final de app/server.js:*/


module.exports = app

Por ltimo podramos utilizar un paquete como istanbul que nos analice el cdigo y ver si
nuestras pruebas recorren todas las instrucciones, funciones o ramas del cdigo:

npm i -D istanbul
./node_modules/.bin/istanbul cover -x "**/tests/**" ./node_modules/.bin/_

Estos datos son facilmente exportables a algn servicio que nos de una estadstica de la
cobertura de nuestros tests o que haga un seguimiento de los mismos entre las distintas
versiones de nuestro cdigo.
Por ltimo tambin se podra integrar con un sistema de integracin continua tipo Travis.

Uso de middlewares
Son funciones que tienen acceso al objeto de solicitud (req), al objeto de respuesta (res) y a la
siguiente funcin de middleware en el ciclo de solicitud/respuestas de la aplicacin.
La siguiente funcin de middleware se denota normalmente con una variable denominada next.

Podemos crear un middleware que guarde traza de las fechas de acceso:

var app = express();

app.use(function (req, res, next) {


117
Creacin de una API con node.js

console.log('Time:', Date.now());
next();
});

Normalmente utilizaremos middlewares que ya estn hechos, por ejemplo Morgan para logs y
cors para Cors.

Los instalamos:

npm i -S cors morgan

Los insertamos en nuestra API (el orden puede ser importante):

var express = require('express') //llamamos a Express


var app = express()
var cors = require('cors')
var bodyParser = require('body-parser')
var morgan = require('morgan')

var port = process.env.PORT || 8080 // establecemos nuestro puerto

/*toda la configuracin de bbdd la hacemos en un fichero a parte*/


require('./db')

app.use(morgan('combined'))
app.use(cors())
app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json())

// para establecer las distintas rutas, necesitamos instanciar el express


var router = require('./routes')
app.use('/api', router)

// iniciamos nuestro servidor


app.listen(port)
console.log('API escuchando en el puerto ' + port)

/*lo aado al final de app/server.js:*/


module.exports = app

118
SPA

SPA
Single Page Applications
Los objetivos de este captulo son:

Entender el concepto de un SPA

119
Arquitectura de un SPA

Arquitectura de un SPA
SPA
Caractersticas de un SPA
Por SPA se conocen las aplicaciones de una sola pgina o Single Page Applications.
La aplicacin se enva al navegador y la pgina no se recarga durante su uso.
Una arquitectura SPA permite realizar cualquier aplicacin tradicional de escritorio va web, ya
que el tiempo de respuesta es mucho ms rpido que el de una aplicacin web tradicional.

Arquitectura de un SPA
La mayor parte de la funcionalidad se lleva al cliente. Lo podramos ver como un fat-client que
se carga desde un servidor web.
El cdigo en servidor se usa bsicamente para proveer de una API RESTful a nuestro cdigo
120
Arquitectura de un SPA

cliente usando Ajax.

Un poco de historia
Plataformas SPA

Las tres plataformas de SPA ms utilizadas (2014) son Java applets, Flash/Flex y JavaScript.
La mejor eleccin es JavaScript por las siguientes razones:
No necesita ningn plugin ni ninguna configuracin de seguridad adicional.
Utiliza menos recursos que introducir otro entorno de ejecucin adicional.
Una pgina ms fluida e interactiva: la interfaz de la aplicacin es la ventana completa
del navegador

Por contra JavaScript ha tardado en ser competitivo principalmente por las inconsistencias entre
los distintos navegadores.
Las otras tecnologas estn desapareciendo:
IPad 1 no ejecutaba Flash en su aparicin en el 2010
Al final del 2015, muchas empresas quitaron o anunciaron que iban a eliminar el soporte
a tecnologas como Flash, Silverlight o Java de sus navegadores.
Oracle propone a los desarrolladores de Java migrar sus applets a Java Web Start.

SPA vs app tradicional

Si comparamos un SPA con desarrollos de aplicaciones de escritorio tradicionales, podemos ver


como tambin hay numerosos puntos a favor de JavaScript:
El navegador es la aplicacin ms utilizada del mundo, ejecutar un SPA es tan sencillo
como hacer un clic en una entrada en la barra de favoritos. El despliegue de la aplicacin
tambin es trivial
Es una solucin multiplataforma
JavaScript se ha vuelto extremadamente rpido gracias a la competencia entre los

121
Arquitectura de un SPA

distintos navegadores

La propia evolucin de JavaScript con el uso de JSON, jQuery, AJAX y muchas libreras
actuales y potentes.
Podemos utilizar JavaScript tanto en cliente como en servidor mediante Node.js.
Existen bases de datos que pueden comunicarse directamente en JSON como CouchDB o
MongoDB
Dadas las ventajas inherentes a JavaScript hay herramientas para trabajar en otros lenguajes de
programacin y que generan posteriormente JavaScript. Un ejemplo es Google Web Toolkit
(GWT) que genera JavaScript desde Java o Cappuccino que utiliza Objective-C.

Problemas de JavaScript

Sin embargo por la naturaleza de un SPA tenamos varios inconvenientes (entre parntesis cito
posibles soluciones):

En JavaScript no hay namespaces (solucionado en ES6)


El tipado es dbil (existen soluciones como Facebook flow o TypeScript)
Enrutamiento en cliente (mltiples soluciones va framework o va libreras)
Cdigo html extenso (no mediante web components)

Frameworks de JavaScript

El uso de frameworks y en especial la aparicin de Angular en 2013 y su gran adopcin en la


comunidad de desarrolladores supuso un fuerte empujn en la facilidad para implementar un
SPA mediante JavaScript. Desde entonces han aparecido una gran cantidad de frameworks y se
extiende el concepto JavaScript fatigue:

Saul: Hows it going?

Me: Fatigued.

Saul: Family?

Me: No, Javascript.

Avances en JavaScript

Las nueva versin de JavaScript (ES2015) ha mejorado muchas carencias del lenguaje como el
uso unificado de mdulos.

Se implementan soluciones para el tipado de datos, ya sea programando en lenguajes


intermedios como TypeScript o mediante soluciones como Flow.

El uso de Polymer o React.js marca la tendencia a trabajar haca web components. Angular 2,
despus de mucho tiempo el 2 de Mayo de 2016 public su Release Candidate.

React.js fue la gran revelacin en el 2015 y parece que ha surgido para quedarse. Ya veremos
que ocurre con Angular2, hay quien dice que llega demasiado tarde....

122
PhoneGap

PhoneGap
PhoneGap
Introduccin
Vamos a crear una pequea prctica con la que aprenderemos las caractersticas bsicas de
Cordova, manejar la API de para usar las caractersticas nativas del dispositivo y a crear una
aplicacin con una arquitectura ptima para mviles.

Echa un vistazo primero al diseo y arquitectura de una aplicacin en PhoneGap. Ah entre


otras cosas aclaro las diferencias entre PhoneGap y Cordova.

Requisitos previos
En el captulo de Entorno de trabajo vimos como instalar Android Studio junto con el JDK
Desde el software de Android Studio podemos instalar los SDK de Android que necesitemos.
Se configuraron tambin los PATH de la mquina necesarios. Si tu usuario es diferente, puede
ser que tengas que cambiar algo.

ADB
ADB son las siglas de Android Debug Bridge
Es una herramienta de desarrollo incluida en el SDK de Android.
Comunica el dispositivo Android o el emulador con el ordenador.
Sirve para instalar aplicaciones, ver ficheros de log, hacer push o pull de ficheros...
Para ver errores utilizaremos:

adb logcat

Emuladores
Mediante android avd podemos definir los emuladores que necesitemos:
No olvides, en Emulation options, marcar la opcin use host GPU

Nuevo proyecto de Cordova


Instalamos Cordova

npm i -g cordova

Creamos nuestro proyecto mediante el comando instalado anteriormente:

cd
cordova create proyecto com.tunombre.proyecto Proyecto

El primer parmetro es el directorio donde se guardar e proyecto. El segundo es un identificador para


el proyecto con estructura de DNS inverso, el tercero es el nombre del proyecto y ttulo que mostrar

123
PhoneGap

la aplicacin. Puede ser til poner el modificador -d para mostrar el progreso de creacin del proyecto

Comprobamos para que plataformas podemos generar nuestro apk:

$ cordova platform ls
Installed platforms:

Available platforms:
amazon-fireos ~3.6.3 (deprecated)
android ~5.1.1
blackberry10 ~3.8.0
browser ~4.1.0
firefoxos ~3.6.3
ubuntu ~4.3.3
webos ~3.7.0

Instalamos la plataforma android (se crear un directorio bajo platforms):

$ cordova platform add android


Adding android project...
Creating Cordova project for the Android platform:
Path: platforms/android
Package: com.juanda.futbolistas
Name: Futbolistas
Activity: MainActivity
Android target: android-23
Android project created with cordova-android@5.1.1
Discovered plugin "cordova-plugin-whitelist" in config.xml. Adding it to t
Fetching plugin "cordova-plugin-whitelist@1" via npm
Installing "cordova-plugin-whitelist" for android

This plugin is only applicable for versions of cordova-android greater tha

Plugins de Cordova

Observa que en el paso anterior se ha instalado un plugin que estar en el directorio de plugins.
Cordova funciona en base a plugins que le van aadiendo funcionalidad a nuestro software, as
el fichero de js no crece demasiado si no es necesario.
Puedes echar un vistazo al directorio de plugins de Cordova y su compatibilidad con las
distintas plataformas mviles.

Los plugins se instalan mediante:

cordova plugin add <nombre-plugin>

Requerimientos de software

Podemos comprobar si cumplimos los requerimientos para el desarrollo:

$ cordova requirements

Requirements check results for android:


Java JDK: installed .
Android SDK: installed
124
PhoneGap

Android target: installed android-18,android-19,android-21,android-22,andr


Gradle: installed

Necesitamos un emulador de Android. Voy a utilizar Android Virtual Device, pero Virtual
Box no permite virtualizacin anidada :-(

Evento deviceready

Si ejecutamos el cdigo base por defecto en un navegador, no funcionar:


El cdigo principal se dispara en el evento deviceready, este evento marca que las APIs
del dispositivo estn ya cargadas y accesibles.
Cordova consiste en dos partes de cdigo: nativo y JavaScript. Mientrase no se carga el
cdigo nativo, aparece la imagen de carga.

Si lo ejecutamos en el emulador, funcionar correctamente:

Lanzamos el emulador

android avd &

Ejecutamos nuestro proyecto:

cordova run android

Aadir un plugin

Vamos a modifica el fichero index.js para que muestre va consola algn dato del dispositivo:

....
receivedEvent: function(id) {
var parentElement = document.getElementById(id);
var listeningElement = parentElement.querySelector('.listening');
var receivedElement = parentElement.querySelector('.received');

listeningElement.setAttribute('style', 'display:none;');
receivedElement.setAttribute('style', 'display:block;');

console.log('Received Event: ' + id);


console.log(device.cordova);
console.log(device.model);
}

Si ejecutamos nuestro proyecto de nuevo, dar un error, se pueden ver trazas mediante:

adb logcat

Instalamos el plugin correspondiente y lanzamos de nuevo el proyecto:

cordova plugin add cordova-plugin-device


cordova run android

Compilacin

Los comandos ms habituales son los siguientes:

125
PhoneGap

El proyecto se ejecuta en el dispositivo fsico y si no existe, en el emulador

cordova run android

El proyecto se ejecuta en el emulador

cordova emulate android

Se genera el apk del proyecto, para poderlo instalar "a mano".

cordova build android

Nuestro entorno de desarrollo

Probaremos todo lo que podamos directamente en el navegador


Si podemos, utilizamos emulador... aunque VirtualBox no soporta virtualizacin anidada
Generamos el apk y lo instalamos en el movil
Necesitamos habilitar sideload (Ajustes->Seguridad->Origenes desconocidos)
El apk se puede enviar de forma cmoda mediante AirDroid o se puede colgar en una url
y acceder va navegador
Para instalarlo basta con hacer doble click
Utilizar Screen Stream Mirroring para compartir la pantalla

Prctica de Cordova
Hacemos un fork de mi repositorio
Hacemos git clone del nuevo repositorio creado
Nos situamos dentro y creamos nuestro proyecto:

cd practica-cordova
cordova create futbolistas com.tunombre.futbolistas Futbolistas

Copiamos los ficheros de nuestra prctica y borramos lo que no nos interesa:

rm futbolistas/www/css/index.css
rm futbolistas/www/js/index.js
cp -r sources/* futbolistas/www/

Test del cdigo base

Probamos el funcionamiento desde el navegador:

cd futbolistas/www
xdg-open index.html

Podemos probar tambin desde el emulador:

cordova platform add android


cordova run android

Mtodo de almacenamiento

Definimos varios mtodos de almacenamiento mediante ficheros y clases independientes.


Todas las clases presenten la misma interfaz de modo que utilizar uno u otro mtodo de

126
PhoneGap

almacenamiento sea transparente para el desarrollo de la aplicacin.


Tipos de almacenamiento:
Almacenamiento en memoria (fichero js/adapters/memory-adapter.js)
Almacenamiento en remoto (fichero js/adapters/jsonp-adapter.js)
Almacenamiento mediante LocalStorage (fichero js/adapters/localstorage-adapter.js)
Almacenamiento en base de datos local (fichero js/adapters/websql-adapter.js)
Descartamos indexDB (no lo soporta PhoneGap ni iOS)
Abre cada uno de los ficheros anteriores para explorar cada uno de los mtodos de
almacenamiento.

Cambiar el tipo de almacenamiento

Prueba la aplicacin con cada uno de los mtodos de almacenamiento anteriores


La aplicacin por defecto est configurada para trabajar con almacenamiento en memoria. Para
cambiar el mtodo de almacenamiento:
En el fichero index.html, cambia el fichero memory-adapter.js por el que corresponda:
jsonp-adapter.js, localstorage-adapter.js, o websql-adapter.js.
En js/app.js, reemplaza la instanciacin de MemoryAdapter con el que corresponda
segn el mtodo de almacenamiento elegido: JSONPAdapter, LocalStorageAdapter, o
WebSqlAdapter.
Prueba la aplicacin

Uso de notificacin nativa

El tpico alert de JavaScript puede ser algo rgido para tu aplicacin PhoneGap que aparenta ser
nativa. Puede ser que queramos personalizar la ventana de aviso mediante un ttulo, un texto
especfico en el botn o incluso una funcin de callback. La funcin alert de JavaScript no nos
lo va a permitir.

Para hacer una llamada a la ventana de dilogo nativa deberemos aadir el plugin
correspondiente:

cordova plugin add cordova-plugin-dialogs

Al utilizar nuestra aplicacin algo nativo, deberemos aadir la librera cordova.js:

<script src="cordova.js"></script>

Esta instruccin hara que Cordova inserte la versin especfica de Cordova a la plataforma en la
que estemos desarrollando en tiempo de compilacin. Es decir, el fichero cordova.js no debera
estar presente en la carpeta www de nuestro proyecto.

Por ltimo deberemos hacer un override de la funcin window.alert() cuando ejecutemos


nuestra aplicacin en un dispositivo que disponga del objeto navigator.notification.alert().
Aadiremos el siguiente cdigo en nuestra aplicacin (fichero app.js, en el bloque de registro
de eventos):

document.addEventListener('deviceready', function () {
if (navigator.notification) {
// Si disponemos de notificaciones nativas, sobreescribimos el alert del nav
window.alert = function (message) {
navigator.notification.alert(
message, // mensaje
null, // funcin de callback
127
PhoneGap

"Workshop", // ttulo
'OK' // Nombre botn
);
};
}
}, false);

Prueba a ejecutar la aplicacin desde el dispositivo mvil o emulador y desde el navegador del
PC. Observa que la notificacin cambia en funcin del entorno.

Evita el retraso de 300ms en el clic


Si pulsas el botn de ayuda y segn el dispositivo/emulador puedes notar cierto retraso hasta
que aparece la ventana de dilogo.

Esto es debido a que el navegador puede esperar en torno a 300ms por si el usuario hace un
doble clic. Para evitarlo podemos utilizar alguna librera de JavaScript como FastClick

Aade el script en el fichero index.html:

<script src="lib/fastclick.js"></script>

Registra FastClick en el fichero app.js. En la documentacin de FastClick se explica como


integrarlo, pero quiz lo ms sencillo sea dentro de la funcin manejadora del evento
deviceready que hemos utilizado en el paso anterior, aadiendo la siguiente instruccin:

FastClick.attach(document.body);

Comprueba desde el emulador o movil que ha desaparecido el retraso si hubiese. En principio


bajo Chrome y al tener el viewport con user-scalable=no, no sera necesario.

Arquitectura SPA
Vamos a configurar ahora nuestra aplicacin para que se ejecute en una sola pgina:

Su funcionamiento ser ms fluido


Pretendemos que la velocidad de ejecucin sea lo ms parecido a ejecutar cdigo nativo.

En el fichero index.html borramos todo el contenido del body (salvo los scripts) ya que lo
generaremos mediante JavaScript

Definiremos una funcin que ser la encargada de renderizar el home de nuestra aplicacin,
dentro de la seccin de funciones locales del script app.js:

function renderHomeView() {
var html = "<header>" +
"<h1>Futbolistas</h1>" +
"</header>" +
"<input id='btnBuscar' type='search' placeholder='Introduc
"<ul id='lstFutbolistas'></ul>"
$('body').html(html);
$('#btnBuscar').on('keyup', encontrarPorNombre);
}

128
PhoneGap

Observa que hemos quitado el botn de ayuda y que el registro del evento keyup lo metemos
dentro de la funcin renderHomeView, por lo que deberemos quitarlo de donde estaba
anteriormente (seccin registro de eventos). Tambin quitaremos el manejador del botn de
ayuda.

Modificaremos la lgica de la aplicacin, de modo que una vez que se inicialice el adaptador de
datos se muestre la vista de la pgina inicial:

adapter.inicializar().done(function () {
console.log("Inicializado: Adaptador de datos");
renderHomeView();
});

Eleccin de framework de CSS


A la hora de mostrar nuestro html en pantalla es importante utilizar un framework css
especfico de mvil, es decir, diseado para un renderizado rpido:

Uso propiedades especficas de css para animaciones, que utilicen la GPU

Evitar el uso de propiedades como box-shadow, border-radius, gradientes o text-align

Ejemplos:

Ionic que viene preparado para funcionar con Angularjs y que se integra perfectamente
con PhoneGap
Intel App Framework que viene preparado con un css especfico para cada plataforma
mvil, para simular ms el aspecto nativo
Adobe (impulsor de PhoneGap) tambie tiene el suyo: Topcoat.

Usaremos Topcoat

Uso de templates: handlebars


Escribir cdigo html desde JavaScript es propenso a errores (comillas simples en vez de dobles,
alternar texto con variables) y adems poco legible.

Utilizaremos templates para desacoplar la definicin de la interfaz de usuario (html) del cdigo.
Si no has usado nunca handlebars, echa un vistazo a la documentacin oficial (es corta) y a un
post de ejemplo de uso de handlebars y otro post de precompilacin de handlebars.

Vamos a crear dos templates, una para la pgina de inicio y otra para mostrar los elementos de
la lista de futbolistas, que guardaremos en la carpeta templates.

En la pgina de inicio y segn la documentacin de topcat.io necesitaremos los siguientes


elementos:

Navigation bar
Search Input
List
Plantilla para la pgina de inicio (fichero templates/home.handlebars):

<div class="topcoat-navigation-bar">
<div class="topcoat-navigation-bar__item center full">
129
PhoneGap

<h1 class="topcoat-navigation-bar__title">Futbolistas</h1>
</div>
</div>
<div class="search-bar">
<input type="search" value="" placeholder="buscar" class="topcoat-search-i
</div>
<div class="topcoat-list">
<ul class="topcoat-list__container list" id="lstFutbolistas">
</ul>
</div>

Plantilla para la lista de futbolistas (fichero templates/listaJugadores.handlebars):

{{#.}}
<li class="topcoat-list__item">
<a href="#futbolistas/{{id}}">
<img src="assets/img/{{imagen}}">
<p>{{nombre}} {{apellido}}</p>
<p>{{equipo}}</p>
<span class="chevron"></span>
</a>
</li>
{{/.}}

Precompilamos las plantillas:

$ npm i -g handlebars #en caso de que no tengamos handlebars


$ handlebars templates/ -f js/templates.js

Cambiamos las funciones de app.js para que carguen el template:

function renderHomeView() {
$('body').html(Handlebars.templates.home());
$('#btnBuscar').on('keyup', encontrarPorNombre);
}

function encontrarPorNombre() {
adapter.encontrarPorNombre($('#btnBuscar').val()).done(function(futboli
$("#lstFutbolistas").html(Handlebars.templates.listaJugadores(futboli
});
}

Copiamos el framework de topcoat dentro de nuestro proyecto. Podemos elegir entre un theme
claro y otro oscuro.

<link href="assets/topcoat/css/topcoat-mobile-light.css" rel="stylesheet">

Cargamos tambin el script de handlebars

Al precompilar, cogeremos el runtime,


Utilizo el plugin de Sublime cdnjs

<script src="http://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/han

Cargamos tambin los templates precompilados:


130
PhoneGap

<script src="http://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/han
<script src="js/templates.js"></script>

Si probamos el resultado, vemos que se le puede dar un toque adicional de diseo. Debemos
crear un fichero style.css que aadiremos a nuestro index.html:

<link href="assets/css/styles.css" rel="stylesheet">

Contenido del fichero assets/css/styles.css:

/*Situamos la caja de bsqueda dentro de un div y le damos el 100% de anch


.search-bar {
padding:10px 10px 12px 8px;
}

.search-bar > input {


width: 100%;
}

a {
text-decoration: none;
color: inherit;
-webkit-touch-callout: none;
-webkit-tap-highlight-color: rgba(0, 0, 0);
}

.list {
list-style-type: none;
border-top: none !important;
}

.list > li {
position: relative;
clear: both;
padding: 0px;
margin: 0px;
}

.list > li:nth-of-type(1) {


border-top: none;
}

.list > li > a {


margin: 0px;
display: block;
height: 57px;
padding: 4px;
}

.list > li > a > p:nth-of-type(1) {


margin: 8px 0px 0px 0px;
font-weight: bold;
}

131
PhoneGap

/*El nombre del juegador en negro, el equipo en gris:*/


.list > li p:nth-of-type(2) {
margin: 0px;
color: #777;
}

/*Las imgenes en la lista, con un ancho fijo, y el texto a su derecha:*/


.list > li img {
width: 57px;
height: 57px;
float: left;
margin-right: 8px;
}

/*Cuando pulsamos en un elemento de la lista, le cambiamos el color*/


.list li:active {
background-color: #d6d6d6;
}

/*Aadimos para que el header no haga scroll:*/


.scroller {
overflow: auto;
/*iOS 4 or lower required an esoteric two finger gesture to scroll element
-webkit-overflow-scrolling: touch;
position: absolute;
top: 141px;
bottom: 0px;
left: 0px;
right: 0px;
}

.chevron {
background: transparent url(../img/next_blue.svg);
background-repeat: no-repeat;
background-size: contain;
width: 20px;
height: 20px;
position: absolute;
right: 12px;
top: 22px;
}

Crear una clase vista


Vamos a dar algo ms de estructura a la aplicacin, adelgazando el fichero app.js.
Nos llevaremos toda la lgica de como crear las vistas a otro fichero-clase, HomeView.js, que
encapsular la lgica de creacin y renderizado de la vista.
Debemos pensar que puede haber muchas vistas, y de este modo, cada una de ellas estar en su
propia clase, sin cargar en exceso el ncleo de nuestra aplicacin, el fichero app.js.

Clase HomeView

Creamos la clase HomeView. El cdigo ser el siguiente:


132
PhoneGap

var HomeView = function (adapter) {


this.inicializar = function () {
// Definimos un div para la vista. Lo usaremos para aadir eventos
this.el = $('<div/>');
this.el.on('keyup', '#btnBuscar', this.encontrarPorNombre);
};
this.render = function() {
this.el.html(Handlebars.templates.home());
return this.el;
//esto es lo que hemos movido de app.js aqu:
//$('body').html(Handlebars.templates.home());
//La siguiente lnea sobra, ya est puesta al inicializar:
//$('#btnBuscar').on('keyup', encontrarPorNombre);

};
//este mtodo lo movemos tal cual de app.js:
this.encontrarPorNombre = function() {
adapter.encontrarPorNombre($('#btnBuscar').val()).done(function (f
$("#lstFutbolistas").html(Handlebars.templates.listaJugadores(f
});
};
this.inicializar();
}

Eliminamos las funciones renderHomeView y encontrarPorNombre de app.js

Cargamos el script de HomeView.js en nuestro index.html antes de cargar app.js:

<script src="js/HomeView.js"></script>

Modificamos la funcin de inicializacin de app.js para que renderice la vista de inicio


mediante la clase HomeView recin creada:

adapter.inicializar().done(function () {
$('body').html(new HomeView(adapter).render());
});

Implementar scrolling
Cuando la lista de futbolistas es mayor que la ventana del navegador, si nos desplazamos, toda
la vista hace scrolling (incluido el header).

Para que el scroll se produzca solo en la lista de futbolistas crearemos una clase adicional en el
fichero assets/css/styles.css con el siguiente contenido:

.scroller {
overflow: auto;
-webkit-overflow-scrolling: touch;
position: absolute;
top: 141px;
bottom: 0px;
left: 0px;
right: 0px;
}
133
PhoneGap

Aade la clase scroller en el div de la lista de jugadores (plantilla home.handlebars)

<div class="topcoat-list scroller">

Por ltimo, no olvides hacer la precompilacin del template antes de comprobar el


resultado!

Enrutado de vistas
Vamos a crear otra vista en la que mostraremos los detalles de cada jugador.
Al tener ahora nuestra aplicacin ms de una vista, habr que implementar algn mecanismo de
enrutado que determine si debemos mostrar la vista de inicio o la de detalle del jugador.

Implementar vista de jugador

Creamos nuestra nueva plantilla, mediante el fichero templates/jugador.handlebars:

<div class="topcoat-navigation-bar">
<div class="topcoat-navigation-bar__item left quarter">
<a class="topcoat-icon-button--quiet back-button" href="#">
<span class="topcoat-icon topcoat-icon--back"></span>
</a>
</div>
<div class="topcoat-navigation-bar__item center half">
<h1 class="topcoat-navigation-bar__title">Futbolistas</h1>
</div>
</div>
<div class="detalles scroller">
<img src="assets/img/{{imagen}}" class="imagen-futbolista">
<h1>{{nombre}} {{apellido}}</h1>
<p><strong>Equipo:</strong> {{equipo}} </p>
<p><strong>Posicin: </strong>{{posicion}}</p>
<p><strong>Dorsal:</strong> {{dorsal}}</p>
<p><em>{{desc}}</em></p>
<div class="topcoat-list__container clearfix">
<ul class="topcoat-list list actions">
<li class="topcoat-list__item"><a href="tel:+34606606606"><p>L
<li class="topcoat-list__item"><a href="tel:+34606606606"><p>L
<li class="topcoat-list__item"><a href="sms:+34606606606"><p>E
<li class="topcoat-list__item"><a href="mailto:micorreo@gmail.
<li class="topcoat-list__item"><a href="#" class="add-location
<li class="topcoat-list__item"><a href="#" class="add-contact-
<li class="topcoat-list__item"><a href="#" class="change-pic-b
</ul>
</div>
</div>

Precompilamos las plantillas al haber creado una nueva:

$ handlebars templates/ -f js/templates.js

Creamos la clase JugadorView con el siguiente contenido (fichero js/JugadorView.js):

var JugadorView = function(adapter, futbolista) {


134
PhoneGap

this.inicializar = function() {
this.el = $('<div/>');
};
this.render = function() {
this.el.html(Handlebars.templates.jugador(futbolista));
return this.el;
};
this.inicializar();
}

Cargamos el script JugadorView.js en el fichero index.html antes del script app.js:

<script src="js/JugadorView.js"></script>

Enrutado

La funcin de enrutado tendr que ir en el fichero app.js.

Creamos una variable con la expresin regular que utilizaremos para mostrar o no la vista de un
jugador en concreto. La guardaremos en la seccin de variables locales del fichero app.js:

var futbolistaURL = /^#futbolistas\/(\d{1,})/;

Definiremos un nuevo listener para cuando haya cambios en el hash de la url, dentro de la
seccin registro de eventos del fichero app.js

$(window).on('hashchange', route);

En la seccin de funciones locales, definiremos la funcin route, que se encargar de enrutar a


la vista concreta.

function route() {
var hash = window.location.hash;
if (!hash) {
$('body').html(new HomeView(adapter).render());
return;
}
var match = hash.match(futbolistaURL);
if (match) {
adapter.encontrarPorId(Number(match[1])).done(function(futbolista) {
$('body').html(new JugadorView(adapter, futbolista).render());
});
}
}

Cambiaremos la lgica de la inicializacin del adaptador, para que llame a la funcin de


enrutado (fichero app.js) para que cargue la vista que corresponda en funcin de la url, en vez
de cargar siempre la de HomeView:

adapter.inicializar().done(function () {
console.log("Inicializado: Adaptador de datos");
//$('body').html(new HomeView(adapter).render());
route();
});

135
PhoneGap

He aadido varios varias lneas al fichero assets/css/style.css para la nueva vista:

/*Todo lo siguiente lo aadimos para modificar la presentacin de la vista

.back-button {
position: absolute;
top: 10px;
}
.topcoat-icon--back {
background: url("../img/back_light.svg") no-repeat;
-webkit-background-size: cover;
-moz-background-size: cover;
background-size: cover;
}
.detalles {
margin: auto;
/*para no utilizar el top que he puesto en scroller:*/
top: 71px !important;
}
.detalles>img {
float:left;
margin:10px;
width: 250px;
height: 250px;
}
.detalles h1 {
padding: 12px 0px 4px 0px;
margin: 0px 0px 0px 0px;
font-size: 1.2rem;
}
.detalles p {
padding: 0px 0px 4px 0px;
margin: 0px 0px 0px 0px;
}
.actions > li > a {
padding-left: 12px;
}
.action-icon {
position: absolute !important;
top: 18px;
right: 20px !important;
width: 28px !important;
height: 28px;
}
.actions li p:nth-of-type(1) {
color: #5DC1FF;
font-size: 0.9em;
font-weight: lighter;
}
.actions li p:nth-of-type(2) {
color: inherit;
}
.icon-call {
136
PhoneGap

background: transparent url(../img/call.svg);


background-repeat: no-repeat;
-webkit-background-size: cover;
-moz-background-size: cover;
background-size: cover;
}
.icon-sms {
background: transparent url(../img/chat.svg);
background-repeat: no-repeat;
-webkit-background-size: cover;
-moz-background-size: cover;
background-size: cover;
}
.icon-mail {
background: transparent url(../img/email.svg);
background-repeat: no-repeat;
-webkit-background-size: cover;
-moz-background-size: cover;
background-size: cover;
}
.clearfix{
clear: both;
}

Por ltimo probamos que el enrutamiento funcione y se muestre la nueva vista.

Uso del API de localizacin


Vamos a mostrar las coordenadas (longitud y latitud) mediante una alerta.
En una aplicacin real, lo guardaramos en una base de datos como parte de la informacin del
futbolista y al visualizar la ficha mostraramos los datos de localizacin en un mapa.
Como hacemos llamada a cdigo nativo, no se podr probar desde un navegador en el PC.

Lo primero es mirar la documentacin de Cordova

Aadimos el plugin de geolocalizacin a nuestro proyecto:

cordova plugin add cordova-plugin-geolocation

Registramos en la funcin inicializar() de clase JugadorView un event listener para el evento


clic en el elemento de la lista Aadir Localizacin (fichero js/JugadorView.js):

this.el.on('click', '.add-location-btn', this.addLocation);

Registramos tambin en la clase JugadorView el manejador de evento addLocation:

this.addLocation = function(event) {
event.preventDefault();
navigator.geolocation.getCurrentPosition(
function(position) {
alert(position.coords.latitude + ',' + position.coords.longitude);
},
function() {
alert('Error obteniendo localizacin');
137
PhoneGap

});
return false;
};

Comprobamos su funcionamiento

Uso del API de contactos


Vamos a permitir aadir a los futbolistas a nuestra lista de contactos
Al igual que en el caso anterior, necesitaremos usar un emulador o dispositivo mvil para
testear el resultado
Lo primero es mirar la documentacin de Cordova

Aadimos el plugin:

cordova plugin add cordova-plugin-contacts

Registramos en la funcin inicializar() de clase JugadorView un event listener para el evento


clic en el elemento de la lista Aadir a Contactos (fichero js/JugadorView.js):

this.el.on('click', '.add-contact-btn', this.addToContacts);

Registramos tambin en la clase JugadorView el manejador de evento addToContacts:

this.addToContacts = function(event) {
event.preventDefault();
console.log('Aadiendo a Contactos');
if (!navigator.contacts) {
alert("El API de contactos no est soportada", "Error");
return;
}
/*Segn doc de Cordova: https://github.com/apache/cordova-plugin-contact

// create a new contact object


var contact = navigator.contacts.create();
contact.displayName = "Futbolista";
contact.nickname = "Futbolista"; // specify both to support a

// populate some fields


var name = new ContactName();
name.givenName = futbolista.nombre;
name.familyName = futbolista.apellido;
contact.name = name;

// save to device
contact.save(
function () {
alert ("Futbolista guardado en los contactos del telfono");
},
function () {
alert("uppps, no ha ido bien: " + contactError.code)
}
);
};
138
PhoneGap

Comprobamos su funcionamiento

Uso del API para la cmara de fotos


Vamos a limitarnos a capturar una nueva foto, sin guardarla de forma persistente.
Mira el funcionamiento de la API en la documentacin de Cordova

Instalamos el plugin necesario:

cordova plugin add cordova-plugin-camera

Registramos en la funcin inicializar() de clase JugadorView un event listener para el evento


clic en el elemento de la lista Hacer una foto nueva (fichero js/JugadorView.js):

this.el.on('click', '.change-pic-btn', this.cambiarFoto);

Registramos tambin en la clase JugadorView el manejador de evento cambiarFoto:

this.cambiarFoto = function(event) {
event.preventDefault();
if (!navigator.camera) {
alert("Camera API no soportada", "Error");
return;
}
var options = { quality: 50,
destinationType: Camera.DestinationType.DATA_URL,
sourceType: 1, // 0:Photo Library, 1=Camera, 2=Sa
encodingType: 0 // 0=JPG 1=PNG
};

navigator.camera.getPicture(
function(imageData) {
$('.imagen-futbolista', this.el).attr('src', "data:image/jpeg;base
},
function() {
alert('Error al obtener la foto', 'Error');
},
options);

return false;
};

139
Web Components

Web Components
Web Components
Aprender a utilizar el framework React.js con todo lo que contiene:
Uso y configuracin bsico de webpack
Crear y usar estilos para componentes web
Enrutamiento en cliente
Utilizar componentes

140
Entorno de desarrollo mediante Webpack

Entorno de desarrollo mediante Webpack


Entorno de desarrollo mediante WebPack
Escenarios
Un sitio web tradicional:
html
css
javascript
Una aplicacin web (SPA):
jade u otra template en vez de html
sass o less en vez de css
CoffeScript, TypeScript, ES6-7 en vez de js (ES5)

Task runners
Necesitamos un compilador que nos genere el cdigo que necesita el navegador: html, css y js
(ES5)
Una SPA depende de bastantes libreras, principalmente de js.
Necesitamos concatenarlas (evitar mltiples http requests)
Consumir dependencias y gestionarlas mediante un gestor de paquetes como npm
Optimizar y comprimir imgenes

Linter de los ficheros para detectar errores


Transpiler si trabajamos con ES6, CoffeScript, TypeScript...
Se utilizan Grunt o Gulp y se configuran en base a plugins que se pueden instalar va npm

Bundlers
El problema con Grunt o Gulp viene cuando se utilizan muchos assets:
Sera til poder dividirlos en paquetes o bundlers de modo que:
Los que no se modifiquen (vendor assets), se separan, de modo que se puedan cachear
Determinadas pginas del sitio necesitan assets extra (panel de administracin)
Webpack y Browserify dan esta opcin

Ejemplo de uso

Aplicacin Hola Mundo


Vamos a crear un Hola Mundo.

La forma tradicional sera:

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
141
Entorno de desarrollo mediante Webpack

<title>Hola Mundo</title>
</head>
<body>
<script>
var element = document.createElement('h1');
element.innerHTML = 'Hola Mundo';
document.body.appendChild(element);
</script>
</body>
</html>

Generacin Hola Mundo mediante webpack


Supongamos que el js del ejemplo anterior lo dividimos en dos ficheros:
main.js:
Nexo de unin entre los js de mi app (en un futuro componentes) y el html
component.js:
Representa un componente que generar un ttulo para mi pgina
Este componente podra recibir parmetros como el texto del ttulo, el estilo o
incluso llamar a otros componentes...

Fichero main
main.js:

'use strict';
var component = require('./component.js');
document.body.appendChild(component());

Fichero component
component.js:

'use strict';
module.exports = function () {
var element = document.createElement('h1');
element.innerHTML = 'Hola Mundo';
return element;
};

Uso bsico de webpack


Instalamos webpack a nivel global:

npm i webpack -g

Compilamos nuestro main.js:

webpack main.js bundle.js

Lo llamamos desde un html:

142
Entorno de desarrollo mediante Webpack

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Hola Mundo con componentes</title>
</head>
<body>
<script src='bundle.js'></script>
</body>
</html>

Lo extiendes con algn subcomponente?


Y si llamramos al main.js en vez del bundle.js?
Error con el require!
El navegador solo entiende ES5

Opciones de webpack
Qu hace webpack?

Junta todo nuestro js en un solo fichero


Divide el js en mdulos
Carga el mdulo inicial

Para ver todas las posibilidades

webpack --help

Ejemplos de uso:
webpack -w main.js bundle.js # se queda como un servicio
webpack -p main.js bundle.js # minified
webpack -d main.js bundle.js # debug con sourcemap

Configuracin de webpack
webpack tiene muchas opciones
Usaremos un fichero de configuracin para personalizarlo
Utilizamos node para montar nuestro entorno de desarrollo (plugins para webpack por
ejemplo)
Instalaremos webpack de forma local a nuestro proyecto

Generacin entorno de desarrollo


Mediante node
Deber estar instalado node y su gestor de paquetes npm
Creamos nuestro proyecto

mkdir hola-mundo
cd hola-mundo
npm init -y

Se genera el fichero package.json con las propiedades del proyecto

143
Entorno de desarrollo mediante Webpack

Usar Webpack en mi proyecto


Desinstalamos webpack (lo tenamos instalado de forma global):

npm remove -g webpack

Instalamos webpack como dependencia de nuestro proyecto:

npm install --save-dev webpack

O ms corto:

npm i -D webpack

Ya tenemos el ejecutable (webpack) para poderlo utilizar. Para ver donde se instala:

npm bin

Estructura de nuestro proyecto


Vamos a crear un Hola Mundo:
Estructura de nuestro proyecto:

/app
main.js
component.js
/build
bundle.js (se crear mediante webpack)
index.html (a mano o mediante webpack)
package.json
webpack.config.js

index.html puede ser:

un fichero esttico
un fichero generado dinmicamente

main.js es la entrada a nuestra aplicacin

component.js es una dependencia


webpack.config.js es el fichero de configuracin de webpack

Fichero de configuracin de webpack


webpack.config.js

var path = require('path');


module.exports = {
entry: path.resolve(__dirname, 'app/main.js'),
output: {
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js',
}
144
Entorno de desarrollo mediante Webpack

};

Generar el fichero indicado en output build/bundle.js

a partir del indicado en entry: main.js


Examina sus dependencias y las incluye en el bundle.

Ejecucin
Ejecutamos webpack:

node_modules/.bin/webpack

Creamos el fichero build/index.html que carge el js


Probamos que muestre Hola Mundo
Este ejemplo y los siguientes los puedes descargar de un repositorio de GitHub

Generacin index.html de forma dinmica


Utilizaremos el plugin HtmlWebpackPlugin para webpack:

var path = require('path');


const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: path.resolve(__dirname, 'app/main.js'),
output: {
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js',
},
plugins: [
new HtmlWebpackPlugin({
title: 'Hola Mundo'
})
]
};

Configurar el build
En los scripts del fichero package.json aadimos la compilacin:

"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},

Ahora podremos ejecutarlo mediante npm run build

No hace falta poner la ruta, ya que npm aade de forma temporal el directorio
node_modules/.bin al PATH.

Aadir CSS
Aadimos nuestro fichero component.css:
145
Entorno de desarrollo mediante Webpack

h1 {
color: red;
}

Lo llamamos desde nuestro fichero component.js:

'use strict';
require("./component.css");
module.exports = function () {
var element = document.createElement('h1');
element.innerHTML = 'Hola Mundo';
return element;
};

Procesar CSS
Webpack debe saber importar ficheros css, para ello necesita 2 loaders:
CSS loader: que importa el fichero CSS y procesa los import y url() que tenga.
Style loader: que procesa el CSS generado por CSS Loader y lo inserta en nuestra pgina
html.

Instalamos los mdulos:

npm i -D css-loader style-loader

Configuramos el mdulo en webpack:

module: {
loaders: [
{ test: /\.css$/, loader: "style-loader!css-loader" }
]
}

Procesar SASS
Cambiamos nuestro fichero component.css por component.scss y con cdigo propio de Sass:

$primary-color: red;
h1 {
color: $primary-color;
}

Cambiamos el require de component.js para que llame al fichero anterior.

Instalamos los paquetes necesarios:

npm i -D sass-loader node-sass

Aadimos el procesado de ficheros scss desde webpack:

module: {
loaders: [
{ test: /\.css$/, loader: "style-loader!css-loader" },
{ test: /\.scss$/, loader: "style-loader!css-loader!sass-loader"
146
Entorno de desarrollo mediante Webpack

]
}

Configuracin para usar Boostrap


Por defecto bootstrap viene con less

npm i -S bootstrap

Aadimos a la configuracin de webpack:

{ test: /\.less$/, loader: "style!css!less"},


{ test: /\.(png|woff|woff2|eot|ttf|svg)$/, loader: 'url-loader?limit=10000

Instalamos los paquetes necesarios:

npm i -D url-loader file-loader less less-loader

Para cargar fuentes (ficheros) necesitaremos un cargador de ficheros file-loader

O mejor url-loader que nos las insertar de forma inline en funcin del peso, ahorrando
peticiones html.

Ejemplo de uso con Bootstrap


Creamos un fichero app/boostrap.less copia de node_modules/bootstrap/less/bootstrap.less

// Core variables and mixins


@import "~bootstrap/less/variables.less";
@import "~./misvariables.less";
@import "~bootstrap/less/mixins.less";

// Reset bootstrap/less/and dependencies


@import "~bootstrap/less/normalize.less";
@import "~bootstrap/less/print.less";
@import "~bootstrap/less/glyphicons.less";
....

Para modificar el fichero mediante Sublime es til seleccionar por columnas (ratn derecho +
Maysculas)
Mi fichero de prueba misvariables.less:

//** Background color for `<body>`.


@body-bg: red;
//** Global text color on `<body>`.
@text-color: #fff;

Lo llamamos desde component.js:

'use strict';
require("./bootstrap.less")
module.exports = function () {
var element = document.createElement('h1');
element.innerHTML = 'Hola Mundo';
147
Entorno de desarrollo mediante Webpack

return element;
};

Ojo, afecta a todo el documento:


Normal, porque es el body
Y porque el CSS es global
Empezamos a ver la pega para trabajar con componentes web?

Bootstrap con Sass


Proceso parecido al anterior, pero instalando un paquete que tenga los fuentes en Sass:
bootstrap-sass
Tambin podemos instalar bootstrap-loader
Usa Sass
Nos permite un fichero de configuracin en YAML o JSON: .bootstraprc

Aadir ESLint
Instalamos ESLint en nuestro proyecto

npm i --save-dev eslint

ESLint: Fichero de configuracin


Gua de configuracin y reglas
Mediante el fichero JSON .eslintrc, por ejemplo:

{
"env": {
"node": true,
"browser": true
},
"globals": {
//place settings for globals here, such as
"exampleGlobalVariable": true
},
"rules": {
//enable ESLint rules, such as
"semi" : [2, "never"]
},
"plugins": [
//you can put plugins here
]
}

Configuracin de reglas
Las reglas pueden tener 3 valores:

0: Desactiva la regla
1: Genera un warning (pero el cdigo no hace un exit)
2: Genera un error y el cdigo hace un exit 1
148
Entorno de desarrollo mediante Webpack

Por ejemplo en el .eslintrc anterior el editor nos marcar como error los ; a final de linea

extend
Lo ms cmodo es utilizar eslint configurado ya por alguien, y luego hacer nuestras pequeas
modificaciones mediante rules.
Si hacemos un PR a repositorios de Airbnb, Google... deberemos ser fieles a su gua de
estilos
Utitlizaremos la gua de Airbnb porque est muy documentada:
https://www.npmjs.com/package/eslint-config-airbnb-base
La podemos modificar, por ejemplo quitando los ; al final de las lneas.

Instalacin configuracin de Airbnb


Lo ms cmodo con el propio ejecutable de eslint:

./node_modules/.bin/eslint --init

Elegimos:

Use a popoular style guide


AirBnB
JSON

Nos crear el fichero .eslintrc.json y dos entradas de dependencias en el package.json:

"eslint-config-airbnb": "^9.0.1",
"eslint-plugin-react": "^5.1.1",

Starter kit
La configuracin de Webpack puede ser mucho ms compleja:
Nos falta poder escribir en ES6 en vez de JavaScript tradicional (transpiler babel)
Utilizaremos JSX (JavaScript XML, especfico de React)
Necesitamos editar en vivo:
Hay que configurar el plugin React Hot Loader
Lo mejor es utilizar un starter kit
Por ltimo aadiremos snippets a Sublime para poder trabajar con React ms rpido

Referencias
http://survivejs.com/webpack/introduction-to-webpack/

149
Caractersticas de ES2015

Caractersticas de ES2015
Caractersticas de ES2015
Arrow functions
Para escribir funciones de forma rpida. Esta caracterstica est presente en otros lenguajes.
Tambin se conoce como lambdas.

var salary = [10000, 20000, 30000];


var with1000Increment = salary.map(x => x + 1000);
console.log(with1000Increment);
// > [11000, 21000, 31000];

Ver cdigo

Si hubiera ms de un argumento, son necesarios parntesis:

var marks = [89, 10, 70];


marks = marks.sort((a, b) => b - a);
console.log(marks);
// > [89,70,10]

Ver cdigo

Arrow Functions to Avoid the "self" Madness

If you are writing JavaScript, I hope you know what "self" is and how ugly it is. We can easily avoid
it with arrow functions.

Here's a stupid example trying to console.log all the meta tags after 100 milliseconds:

$('meta').each(function() { setTimeout(() => { console.log(this.name); }, 100); }); Live Code:


https://goo.gl/xUrZSG If there were no arrow functions, we would need to write it like this:

$('meta').each(function () { var self = this; setTimeout(function () { console.log(self.name); }, 100);


});

Creacin de objetos
Se reduce la sintxis para la creacin de objetos:

var name = "Arunoda";


var user = {
name,
getAddress() {
return "Colombo. Sri Lanka";
}
};

Ver cdigo
150
Caractersticas de ES2015

Antes de ES2015 se hubiera escrito as:

var name = "Arunoda";


var user = {
name: name,
getAddress: function() {
return "Colombo. Sri Lanka";
}
};

Variables en cadenas
Desde ES2015 se evita la necesidad de utilizar el operador de concatenacin (+):

var name = "Arunoda";


var address = "Colombo, Sri Lanka";

var greeting = `My Name is ${name} and I live in ${address}`;


alert(greeting);
// Note the use of "`" character

Ver cdigo

Tambin en multilnea:

var blogPost = `
## My First Blog Post

I like to write in Markdown!


`

Ver cdigo

Destructuring and Matching

With this feature, you can reduce the amount of code and self-document it.

Let's say we have a user object and we are only interested in the name field. This is how we can do it
with ES2015:

var user = {name: "arunoda", address: "Colombo. Sri Lanka"}; var {name} = user;
console.log(name); This seems kind of weird at first. But its very useful when you are working on a
real app. Let's say I want to get the target of a click event. Here's how:

$("body").click(function({target}) { console.log(You clicked on ${target}); }); Live Code:


https://goo.gl/uFwzx8 You can also use this to self-document code when accepting an object into an
API. For example, lets say I have a function that accepts an object that has name and address. Then it
prints a greeting. This is how we can do it with destructors:

function GreetUser({name, address="N/A"}) { console.log(${name}'s address is:


${address}); }

GreetUser({name: "Arunoda"}); Live Code: https://goo.gl/OgWhrD Argument Spreading and the


Rest Operator

151
Caractersticas de ES2015

In JavaScript, we can accept any number or arguments. But this feature is kind of difficult to handle.
ES2015 makes it pretty simple.

Let's implement a function like Meteor.subscribe:

function MySubscribe(name, ...params) { var paramsString = params.join(", ");


console.log(Subscribing to ${name} with "${paramsString}"); }

MySubscribe("getPost", "meteor-category", "postId"); Live Code: https://goo.gl/zLDEKi You can


also use the spread operator to pass an array of arguments to a function. See:

function MySubscribe(name, ...params) { var paramsString = params.join(", ");


console.log(Subscribing to ${name} with "${paramsString}"); }

var params = ["meteor-category", "postId"]; MySubscribe("getPost", ...params); Live Code:


https://goo.gl/zAx2uf

152
Evolucin del CSS

Evolucin del CSS


Evolucin del CSS
Origen del css
Se invent parar la presentacin del marcado semntico (html 5)
Ejemplo en CSS Zen Garden
Fue un cambio radical en los tiempos en que los layouts estaban basados en tablas

Documentos vs Webapps
Cuando pensamos en sitios web sencillos, tenemos un pensamiento global para todas las
pginas:
Mismo header, footer, tipo de lista, prrafos...
A todas las pginas se les aplican los mismos estilos
El global scope o mbito global del CSS tiene sentido
Si nuestro sitio se vuelve complejo la cosa cambia:
El global scope y un mantenimiento fcil dejan de ser sinnimos
Es lo mismo que pasa en un lenguaje de programacin con los mbitos de las variables

Forma clsica de hacer CSS


Como el CSS tiene mbito global:
Las clases css que definimos puden provocar estilos no deseados en algn componente.
Puede haber incompatibilidades entre dos componentes (clases coincidentes)
Tendremos que utilizar selectores suficientemente especficos para evitar ese tipo de
errores. Se opta por diversas soluciones como OOCSS (Object CSS) y BEM:

.Block__Element--Modifier {....}

Ejemplo de BEM

Se usa en Material design:

<ul class="menu">
<li class="menu__item">
<a class="menu__link">
<span class="menu__text"></span>
</a>
</li>
</ul>

La metodologa es utilizar selectores que sean fciles de reusar, como es el selector class.
Ponemos ciertas restricciones a nuestro uso de CSS:

/* BIEN */
.alert {
font-weight: bold;
153
Evolucin del CSS

}
.danger {
color: red;
}
/* MAL, menos reusable */
.alert.danger {
font-weight: bold;
color: red;
}

Separar el contenedor del contenido (los containers no tienen que tener estilos visuales, lo que
sera el theme)

Ejemplo con Bootstrap

Ejemplo tpico de OOCSS. Se usan numerosas clases:

btn
btn-default, btn-primary, btn-success....
btn-lg, btn-sm, btn-xs
disable, active

Se utiliza un grid system con o sin media queries


Layout helpers (visible-sm...)
Reglas bsicas sin usar clases!
Selector de etiqueta (h1, p, a ....)
Selector etiqueta con descendente (h1 em)
Selector etiqueta con hijo (ul>li)
Reset de los estilos del navegador
Normalmente agrupamos estilos por categoras (grid, botones, tipografa, imgenes...)
Usamos preprocesadores como Less, Sass o Stylus.

Web Components
Van a llegar los web components al browser... aunque ya tiene algunos:

<select>
<option>....</option>
<option>....</option>
</select>

<input type="date" />

Situacin actual

Polymer crea polyfills para que se puedan usar


Angular tiene sus directives
React es el que "tiene el mercado" desde el 2015:
Todo son componentes
No hay otro tipo de elementos como controllers

Directrices para hacer web components

154
Evolucin del CSS

Las imgenes que usa el componente pertencen al componente


El css que usa el componente pertenece al componente
No nos interesan los detalles de implementacin del web component (ej. datepicker)

Web components de terceros

jQuery UI Date Picker (que horror: ficheros, css...)


Se automatizan las tareas con herramientas como Grunt o Gulp

Desarrollo actual de componentes

Significa pensar en herramientas como webpack que integran imagenes y css dentro del
JavaScript:

require('./MyComponent.css')
const MyComponent = () => (
<div className='MyComponent'>
<div className='MyComponent__Title'>....</div>
...
</div>
</div>
);
export default MyComponent

Cuando queremos usar el componente todos sus assets nos dan igual:

import MyComponent from 'MyComponent';

CSS mediante JavaScript


Inconvenientes

Server render CSS: hay que extraer el CSS que genera el JS mediante algn plugin de webpack
ver: http://stackoverflow.com/questions/34615898/react-server-side-rendering-of-css-modules
:hover, :focus, :active
Media queries
Prefijos por navegador

Soluciones

Aparecen libreras de JS que intentan solventar los problemas:


Radium
[https://github.com/Khan/aphrodite]Aphrodite (de la Khan Academy)
Tabla comparativa: CSS en JS

CSS Modules
No queremos hacer CSS con JavaScript

import styles from './MyComponent.css'


const MyComponent = () => (
<div className={styles.header}>
<div className={styles.title}>....</div>
155
Evolucin del CSS

...
</div>
</div>
);
export default MyComponent

Fichero css:

:local (.header) {.....}


:local (.title) {....}

Las clases se convierten en clases nicas globales


Se evitan colisiones de nombres
Se utilizan hashes pero se puede hacer ms legible (tipo BEM pero "gratis")
Como casi todo tiene ambito local se opta porque sea el valor por defecto (as no hay que
marcarlo), mediante postcss-local-scope.
Configuracin webpack: se debe aadir: css-loader?module

Composicin:

.foo {
composes: heading from '/typography.css';
composes: box from 'layout.css';
color: red;
}

@value para colores, media queries... https://github.com/css-modules/postcss-modules-values

react-themeable -> styles are props to components

Radium
ReactCSSTransitionGroup -> Minuto 31

156
Reactjs

Reactjs
React.js
Desarrollado por facebook y utilizado en su sitio web
Quin usa React?
Instagram est realizado completamente con React
Airbnb
Uber
Netflix
....
Sirve para simplificar el diseo de interfaces de usuario complejas

Requisitos
JavaScript
npm
ES2015

Componentes
React se basa en componentes
Utilizaremos clases de JavaScript (ES2015)
Si un componente es complejo se divide en componentes ms simples
Cada componente es como una funcin:
Genera una salida cuando se ejecuta: mtodo render()
La ejecucin se produce sobre un dom virtual

Virtual Dom
Permite que React sea muy rpido
React utiliza el DOM Virtual para hacer los mnimos cambios posibles en el DOM real
La renderizacin en el navegador es mucho ms rpida
Se ejecuta un diff entre el dom virtual y el dom real y se actualizan solo las diferencias.

Primeros pasos
Aunque no es lo habitual en los tutoriales de React:

Vamos a partir de un escenario con Webpack

Utilizaremos un starter kit:


Evitamos la configuracin de webpack que suele ser compleja

Aadiremos snippets a Sublime para poder trabajar con React ms rpido

Hola Mundo

157
Reactjs

Clonamos el starter kit, instalamos dependencias y lo editamos

git clone https://github.com/gaearon/react-hot-boilerplate


cd react-hot-boilerplate
npm install
subl .

Cambiamos el texto en src/app.js y comprobamos que cambia de forma automtica


Aade un prrafo. Qu ocurre?

JSX
JSX = JavaScript XML
Todo lo que devuelve el mtodo render se escribe en JSX
Conseguimos cdigo html legible (sin comillas) dentro de js
Mezclamos JavaScript con html?
... y dentro de poco tambin CSS
Si, no pasa nada: es un componente web

Mezclamos todo?
render debe devolver un nico elemento html
El atributo class de html es una palabra reservada de JavaScript, por lo que en JSX se utiliza
className
Las variables en JSX se ponen mediante llaves

import React, { Component } from 'react';

export default class App extends Component {


render() {
var respuesta = 'Hola, buenos das!'
return (
<div>
<h1>Hola Mundo</h1>
<p className="rojo">{respuesta}</p>
</div>
);
}
}

Funcion map
Es bastante habitual utilizar la funcin map cuando manejamos arrays:

import React, { Component } from 'react';

export default class App extends Component {


render() {
const famosos = [ 'Oliver Khan', 'Albert Einstein' ]
return (
<div>
{famosos.map(famoso => <h1>{famoso}</h1>)}

158
Reactjs

</div>
);
}
}

Ejercicio:

Cmo implementaras el mtodo render si adems de los famosos tuvieras que mostrar sus
comentarios?
Utiliza como ejemplo este array de objetos:

var comentarios= [
{autor: 'Oliver Khan', frase: 'Ultimamente veo ms los abdominales de Cristi
{autor: 'Albert Einstein', frase: 'Dos cosas son infinitas: el universo y la
]

Solucin:

import React, { Component } from 'react';

export default class App extends Component {


render() {
var comentarios= [
{autor: 'Oliver Khan', frase: 'Ultimamente veo ms los abdominales de Cr
{autor: 'Albert Einstein', frase: 'Dos cosas son infinitas: el universo
]
return (
<div>
{comentarios.map(comentario => <div><h1>{comentario.autor}</h1><p>{com
</div>
);
}
}

Comunicacin entre componentes


Vamos a hacer algo similar al ejercicio anterior pero con nuestras cervezas. Lo primero es carga el
fichero cervezas.json y renderzarlo en un navegador. Para poder cargar el fichero cervezas.json desde
nuestro JavaScript tendremos que configurar Webpack:

Instalamos un loader de json para webpack:

npm i -D json-loader

Configuramos Webpack para que utilice el loader:

module.exports = {
...
module: {
loaders: [
{ test: /\.json$/, loader: "json-loader" }
]
}
}
159
Reactjs

Escribimos nuestro componente, modificando ligeramente el del ejercicio anterior:

import React, { Component } from 'react'


export default class App extends Component {
render() {
var cervezas = require('./cervezas.json')
return (
<div>
<h1>Mi lista de cervezas</h1>
{cervezas.map(cerveza => <div><h2>{cerveza.Nombre}</h2><p>{cerveza.
</div>
);
}
}

Por ltimo, descargamos nuestro json de las cervezas, en el mismo directorio que el
componente App:

wget https://raw.githubusercontent.com/juanda99/proyecto_web_basica/master/cer

Si vemos en la consola del navegador, observaremos un error que luego solucionaremos:

Warning: Each child in an array or iterator should have a unique


"key" prop. Check the render method of `App`.

Cada elemento del DOM virtual puede corresponder a un elemento del DOM real y la forma de
conseguir la trazabilidad es mediante la propiedad key.

Intentemos ahora hacer una cosa en la que React es muy bueno: simplificando cdigo, haciendo
las cosas sencillas. Ahora mismo nuestro cdigo tiene dos pegas:
Nuestra clase App define la renderizacin de las cervezas:
Debera indicar que hay que renderizar cervezas
Otra clase llamada Cerveza debera ser la que tuviera los detalles de como
renderizarlas.
El cdigo se ve algo complejo, quiz mejore al crear la clase Cerveza, pero podis pensar
adems que se mezcla el cdigo js con el cdigo en html de forma que queda poco
legible.

Creamos el componente Cerveza

Pensando en componentes, ahora mi class App representa una lista de cervezas. La renderizacin de
cada cerveza puede ser muy simple o muy compleja. Quiz nos interese tener una clase especfica
para representarla:

import React, {Component, PropTypes} from 'react'

export default class Cerveza extends Component {


render() {
return (
<div id={this.props.key}>
<h1>Marca: {this.props.marca}</h1>
<p>Envasado: {this.props.envase}</p>
</div>
)

160
Reactjs

}
}

En el cdigo de la App llamaremos a la clase:

import React, { Component } from 'react';


import Cerveza from './Cerveza.js'
export default class App extends Component {
render() {
var cervezas = require('./cervezas.json')
return (
<div>
{cervezas.map(cerveza => <Cerveza key={cerveza.Nombre} marca={cerve
</div>
);
}
}

Organizando un poco el cdigo de la App:

import React, { Component } from 'react';


import Cerveza from './Cerveza.js'
export default class App extends Component {
getCervezas() {
var cervezas = require('./cervezas.json')
return cervezas.map(cerveza =><Cerveza key={cerveza.Nombre} marca={cer
}
render() {
let cervezas = this.getCervezas()
return (
<main>
<h1>Mi lista de cervezas</h1>
{cervezas}
</main>
);
}
}

Algunos detalles del cdigo:


La funcin getCervezas debera ser una llamada Ajax al servidor
Las propiedades de la clase Cerveza las mandamos mediante atributos html
La clase Cerveza accede a sus atributos mediante this.props y puede comprobar el tipo de
datos recibidos mediante:

static propTypes = {
marca: PropTypes.string,
envase: PropTypes.string,
key: PropTypes.string
}

Estado de los componentes


Cada componente puede tener uno o varios estados adems de sus propiedades. Estos estados son

161
Reactjs

intrnsecos al componente y no dependen de componentes superiores (si no, los pasaramos por
propiedades). Hay que tener en cuenta 3 cosas:

Es mejor tener componentes sin estado (ms reusables)


Los estados se definen en el constructor de clase mediante this.state
Si queremos modificar un estado, se debe utilizar el mtodo this.setState (no se puede modificar
directamente)

Siguiendo con el ejemplo anterior, vamos a recibir tambin la descripcin de la cerveza de forma que
habitilitaremos un botn en cada componente Cerveza para mostrar o no la descripcin de la misma.

import React, {Component, PropTypes} from 'react'

export default class Cerveza extends Component {


static propTypes = {
marca: PropTypes.string.isRequired,
envase: PropTypes.string,
key: PropTypes.string,
desc: PropTypes.string
}
constructor(props) {
super(props)
this.handleClick = this.handleClick.bind(this)
this.state = {
mostarDescripcion: false
}
}

handleClick(){
this.setState({mostrarDescripcion: !this.state.mostrarDescripcion})
}

render() {
var {key, marca, envase, desc} = this.props
var descripcion = this.state.mostrarDescripcion ? <textarea>{desc}</textar
var textoBoton = this.state.mostrarDescripcion ? 'Quitar descripcin': 'Mo
return (
<div id={key}>
<h1>Marca:{marca}</h1>
<button onClick={this.handleClick}>{textoBoton}</button>
<p>Envasado: {envase}</p>
{descripcion}
</div>
)
}
}

Es importante ver que el pulsar sobre el botn no tiene un efecto directo sobre el dom (virtual), sino
sobre el estado del elemento. El cambio del estado hace que se renderice todo el elemento y que
entonces cambien tanto el texto del botn como la visibilidad del textarea. Esto hace que el cdigo en
react sea ms legible y fcil de manetener que por ejemplo en jQuery.

Ajax
162
Reactjs

Mediante jQuery o mediante XMLHttpRequest


No utilizamos jQuery
XMLHttpRequest tiene una sintaxis complicada
Podemos utilizar fetch, que adems devuelve promesas
En la vista
Cundo se hace la llamada?
Nunca en el render: infinity asyncronous loop
React tiene unos mtodos predefinidos que nos pueden servir :-)

Mtodos en React

constructor()
componentWillMount()
render()
componentDidMount()
componentWillUnmount()

Normalmente las llamadas ajax se hacen dentro del componentDidMount:

import React, { Component } from 'react'


import Cerveza from './Cerveza'
import 'whatwg-fetch'
export default class App extends Component {
mostrarCervezas(cervezas) {
return cervezas.map(cerveza =><Cerveza key={cerveza.Nombre} marca={cer
}

obtenerCervezas() {
var that = this
var misCervezas = fetch('http://localhost:8080/api/cervezas')
misCervezas.then(function(response) {
return response.json()
}).then(function(data) {
console.log('parsed json', data)
that.setState({
cervezas: data
})
}).catch(function(cervezas) {
console.log('parsing failed', cervezas)
})
}

constructor(props) {
super(props)
this.state = {
cervezas: []
}
}

componentDidMount() {
this.obtenerCervezas()
}
render() {

163
Reactjs

let cervezas = this.mostrarCervezas(this.state.cervezas) || ''


return (
<main>
{cervezas}
</main>
)
}
}

Actualizaciones

Si queremos ver si la lista de cervezas ha aumentado, tenemos varias opciones:

Preguntar peridicamente al servidor, que es lo que se conoce como polling

componentDidMount() {
this.timer = setInterval(() => this.obtenerCervezas(), 10000)
}

Nuestro componente no se ver afectado por las numerosas llamadas, ya que si no


hay actualizaciones el DOM no se modifica (diff con el Virtual DOM)
Sin embargo, pueden parecernos numerosas y a menudo innecesarias llamadas que
perjudican la escalabilidad del sistema.
Ojo, tendremos que acordarnos de quitar el timer al eliminar el componente
(cambio de pgina en un SPA):

componentWillUnmount(){
clearInterval(this.timer)
}

Otra opcin es utilizar websockets, como veremos posteriormente.


Es una opcin de ms bajo nivel
Utilizar un framework como Meteor nos facilitar la tarea

164
Real Time

Real Time
Real Time
Qu es real time?
La pregunta podramos hacerla de otra forma... cundo un usuario tiene la sensacin de que cuando
utiliza una aplicacin esta le responde con informacin en tiempo real?

Esto puede ser relativo al tipo de aplicacin: no es lo mismo una reserva de avin o de autobs que
una compra en bolsa. Sin embargo tampoco es lo mismo una compra en bolsa para usuarios que
operan en intrada y usuarios que lo hacen en largo plazo. Su concepto de tiempo real difiere
enormemente.

Long Polling

Short Polling

Suscripciones

http://stackoverflow.com/questions/4642598/short-polling-vs-long-polling-for-real-time-web-
applications

http://stackoverflow.com/questions/10028770/html5-websocket-vs-long-polling-vs-ajax-vs-webrtc-
vs-server-sent-events

Realizaremos un ejemplo con Meteor.

165
Proyectos solucionados

Proyectos solucionados
Prcticas solucionadas
A continuacin se presentan las cuatro prcticas solucionadas. Estn tambin colgadas en los
repositorios de GitHub correspondientes, bajo la rama de Soluciones.

166
Proyecto Web bsica

Proyecto Web bsica


Proyecto Web bsica
Pasos previos
De aqu en adelante utilizaremos emmet para producir de forma rpida el cdigo html del sitio y
git/GitHub para el control de versiones. Toda la solucin que propongo est pensado para trabajar con
el editor de cdigo Sublime Text y con el plugin de Emmet instalado.

Realizamos un fork del repositorio del ejercicio (desde GitHub)


Realizamos un clone de nuestro fork y lo editamos mediante Sublime Text:

cd
git clone <url>
cd proyecto_web_basica
subl .

Generacin del cdigo html del sitio


Cdigo html comn

Creamos la estructura de directorios para la aplicacin (css, img, js).


Creamos nuestro fichero de estilos css/style.css que de momento estar vaco.
Copiamos el logo al directorio img.
Creamos un fichero index.html en el que generamos el cdigo comn con el resto de las pginas
del sitio (bsicamente header, footer y aside). No te olvides de instalar el plugin Emmet y
marcar el fichero como html para que Emmet funcione

Esqueleto html5:

! + tab

Hoja de estilos en el head del documento (la voy a llamar css/style.css).


Para rellenar el atributo href puedes usar el plugin AutoFileLoad

link + tab

Creamos la estructura principal del body (todo junto, sin espacios):

header+aside+main+footer

Creamos el contenido del header:


Observa que utilizo ya clases que utilizar luego para hacer estilos.
Es la forma ms reusable y aporta cierta semntica que nos ayudar a la hora de
hacer el diseo.
No te olvides de rellenar los mens y el src del logo (img/logo.png)!

img.logo+h1.title{Mis cervezas}+p.subtitle{Aficiones y locuras de un amante de

167
Proyecto Web bsica

Creamos el contenido del aside:

div*2>(h1.bannerTitle+div.bannerBody>p*2>lorem)

Creamos el contenido del footer:

p.copyright{Sitio web realizado por un amante de la cerveza}

Completa el men y si todo est correcto, es el momento de clonar el contenido hecho hasta
ahora al resto de ficheros del sitio web (ficheros cervezas.html y contactar.html). Puedes
hacerlo desde Sublime Text instalando el plugin SideBarEnhancements

Pulsa CTRL + MAYS + H para formatear el cdigo desde Sublime Text (plugin HTML
Prettyfy)

Comprueba que el cdigo html5 sea vlido, ya sea va web o mediante plugin del editor de
cdigo (plugin w3cvalidators). Si te da algn warning por mltiples h1 no es importante.

Sera un buen momento para tener nuestra primera instantnea de nuestro trabajo. Realiza
primero una validacin del cdigo html

git status
git add -A
git commit -m "Generada estructura y cdigo base"
git push

index.html

Copiamos el cdigo del fichero noticias.txt en el main del documento index.html.


Ahora debemos convertirlo a html de modo que el cdigo quede similar a lo siguiente:

<main>
<article>
<header>
<h1 class="newstitle"><a href="">Como se tira la cerveza</a></
<p class="newsdate">17 de Mayo de 2016</p>
</header>
<p>Quienes ms saben de esto recomiendan la tirada especial o en d
<p>El primer tiempo consiste en llenar tres cuartas partes de la c
<p>Los expertos consideran que algunas modas, como las de congelar
</article>
<article>
<header>
<h1 class="newstitle"><a href="">El consumo moderado de cervez
<p class="newsdate">14 de Mayo de 2016</p>
</header>
<p>El informe fue presentado por el centro Cerveza y Salud con la
<p>Varios componentes de la cerveza: la fibra soluble, los compues
</article>
</main>

Lo ms prctico para conseguir lo anterior es utilizar emmet: hacer selecciones mltiples y


"envolver" el texto con tags (pulsando CTRL+ALT+G)

Comprueba el document outline del documento. Puedes utilizar la extensin HTML5 Outliner
168
Proyecto Web bsica

de Chrome. Mira un ejemplo de como puede quedar.

Una vez lo tengamos terminado, a guardar nuestra versin del doc:

git status
git add <ruta/index.html>
git commit -m "rellenado cdigo del main"
git push

cervezas.html

Es una tarea similar al caso anterior, sin embargo lo primero que debemos hacer es dejar
nuestro fichero json como un texto plano que ser lo que envolveremos luego en nuestras tags
de html.

Aqu enumero unas indicaciones para hacerlo (hay muchas formas)

Ajuste de lnea en Sublime Text:

Men Preferences->Settings user, insertar campo en el json:


"word_wrap": true

Obtener multicursor a principio de todas las lnas: seleccionando por columna (botn derecho y
maysculas).

Utilizar multicursor al final de todas las lneas:

CTRL + A para seleccionar todo el texto


CTRL + MAYS + L para ir al final
Pulsamos en cursor para dejar de seleccionar todo

Reemplazar texto: CTRL + MAYS + f

Y ahora a guardar las modificaciones en GitHub...

contacto.html

Aadimos el siguiente cdigo dentro del main:

<h1>Contactar</h1>
<p>No me interesa conocerte. Si sabes de alguna cerveza que merezca la pen
<p>Quiz me anime y la ponga en la lista!</p>
<form action="contactar.php">
<div>
<label for="cerveza">Nombre</label>
<input type="text" name="cerveza" id="cerveza">
</div>
<div>
<label>Descripcin</label>
<textarea name="desc" id="desc" cols="30" rows="10"></textarea>
</div>
<div>
<input type="submit" value="Enviar">
</div>
</form>
169
Proyecto Web bsica

CSS general

Vamos a hacer el css bsico:

header, footer {
background-color: orange;
}

En principio es mejor no dar altura a header o footer. No queremos dar lmites que hagan que
los elementos se salgan de su contenedor.
El color de fondo no se pinta en todo el ancho, por culpa del margen del body, as que aadimos
la libera normalize que se encarga de estndarizar ciertos valores comunes en todos los
navegadores:

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/

Para aadir las libreras lo mejor es utilizar el plugin cdnjs con la opcin cdnjs: search (o
pulsando botn derecho)

Modificamos el tamao del logo de la pgina mediante CSS:

.logo{
width: 60px;
height: auto;
margin: 5px;
float: left;
}

Si tenemos claro el tamao mximo de la imagen se podra reducir:

sudo apt-get install imagemagick


convert logo.png -resize 60 logo2.png

Observa que ahora el header ha quedado "desplazado" haca abajo.

header, footer {
background-color: orange;
overflow:hidden;
}

El men queremos que quede horizontal. Utilizamos la propiedad inline-block para el display
porque queremos separar los elementos del men. Qu pasa si pones inline? El navegador te
entiende? Es el momento de instalar si no lo tienes todava, un linter para css...

.menuitem {
display: inline-block;
margin: 5px;
}
.menulink {
text-decoration: none;
}
.menulink:hover {
color: white;
}

170
Proyecto Web bsica

Si ahora queremos colocar el men a la altura de la foto, tendremos que transformar elementos
con un display de tipo bloque (h1 o p y nav en elementos flotantes, de modo que puedan
coexistir en la misma altura):

nav {
float: right;
}

.subtitle {
float:left;
}

Upps, algo se ha estropeado... al poner elementos en flotante, el header no se entera de que


estn y no los tiene en cuenta. Lo podemos solucionar as:

header {
overflow: hidden;
}

Quitamos mrgenes en el ttulo para que quede mejor y ajustamos tambin el footer:

.title {
margin-bottom: 0;
}
.subtitle {
margin-top: 0;
float:left;
}
.copyright {
text-align: center
}

CSS responsive
ViewPort

No podemos trabajar con containers de tamao fijo a no ser que haya unas media queries
previas. La anchura de la pgina web la deben marcar las caractersticas del navegador cliente.
Lo primero es configurar el view port:

meta:vp + tab
<meta name="viewport" content="width=device-width, initial-scale=1">

La etiqueta anterior, as como el css de normalize, lo tendramos por defecto si hubieramos


escogido como plantilla base la proporcionada por el htmlboilerplate. Tambin podras usar un
plugin de Sublime.

Menu responsive

Vamos a centrarnos ahora en el diseo en funcin de media queries. Y empezaremos por la


vista mvil (criterio mobile first).

Lo primero que necesitamos es un botn:

171
Proyecto Web bsica

<nav>
<button onclick="toggle_visibility('menu');" class="btnmenu">Menu</but
<ul id="menu" class="menu">
...

El botn har que se muestre o no el men. Esa interaccin con el usuario, debe hacerse con
JavaScript:

<script type="text/javascript">
function toggle_visibility(id) {
var e = document.getElementById(id);
if(e.style.display == 'block')
e.style.display = 'none';
else
e.style.display = 'block';
}
</script>

En principio el botn, el men, o el subttulo estarn visibles o no, en funcin de media queries:

@media screen and (max-width: 700px) {


.btnmenu {
position: absolute;
top: 25px;
right: 15px;
}
.menu, .subtitle {display: none;}
}

@media screen and (min-width: 701px) {


.btnmenu {
display: none;
}
}

Anchura de la pgina

Pondremos un contendedor de modo que la anchura de la pgina sea


1190px para anchos a partir de 1200px
Todo el ancho menos 5px para mviles (hasta 700px)
690px para anchos entre 700px y 1000px
990 px para anchos entre 1000px y 1200px

El cdigo podra ser similar al siguiente:

.container {
margin: 0 5px;
}
@media screen and (min-width:701px) {
.container {
width: 690px;
margin: 0 auto;
}
}
172
Proyecto Web bsica

@media screen and (min-width:1001px) {


.container {
width: 990px;
}
}

@media screen and (min-width:1201px) {


.container {
width: 1190px;
}
}

Banners a dos columnas

Nuestro cdido se empieza a complicar, quiz sera buena idea ir creando stylesheets
especficas

El navegador solo descargar las que necesite


Puede ser buena idea que se cargue ms de una de modo que se permite reutilizar el
cdigo, aplicamos criterio mobile first.

<link rel="stylesheet" media="screen and (min-width: 701px)" href="css/sma


<link rel="stylesheet" media="screen and (min-width: 1001px)" href="css/me
<link rel="stylesheet" media="screen and (min-width: 1201px)" href="css/la

Para situar los banners a dos columnas optaremos por hacerlo a partir de 1001px. El cdigo del
fichero medium.css quedar as:

.container {
width: 990px;
overflow: auto;
}
aside {
float: left;
width: 20%;
}
main {
float: left;
width: 80%;
}

Plantillas

Para realizar plantillas podemos utilizar Handlebars.


Creamos un fichero templates/header.handlebars para la plantilla del header
Creamos otro fichero templates/footer.handlebars para la plantilla del footer
...

Generamos todas las plantillas mediante el comando:

npm i -g handlebars
handlebars templates/ -f js/templates.js

En nuestros ficheros html habr que cargar, tanto las plantillas como el js que las lea:
173
Proyecto Web bsica

<script src="http://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/handl
<script src="js/templates.js"></script>

Sustituimos por ejemplo el cdigo del header (que ir ahora en templates/header.handlebars)


por lo siguiente:

<div id="header"></div>

Y por ltimo ejecutamos un script dentro de nuestro html que cargue la plantilla del header en
la etiqueta #header anterior:

<script>
document.getElementById("header").innerHTML = Handlebars.templates.hea
</script>

Fuentes?
Uso de Google Fonts
Usar rem y probar funcionamiento

174
Web con bootstrap y gulp

Web con bootstrap y gulp


Web con bootstrap y gulp
Instalacin
Se trata de seguir trabajando el ejercicio de la prctica anterior pero con un entorno de
desarrollo ms potente.

De los generadores para Yeoman, utilizar webapp

Instalo las dependencias:

npm i -g yo gulp-cli bower


npm i -g generator-webapp

Creo mi aplicacin

mkdir proyecto
cd proyecto
yo webapp

Seleccionaremos Sass, Bootstrap y Modernizr. No haremos test, as que da igual BDD que
TDD.

Eliminamos el body del fichero app/index.html con cuidado de no borrar las llamadas a las
hojas de estilos y js, ni los comentarios previos ni posteriores

Podemos dejar el fichero app/styles/main.scss simplemente as:

$icon-font-path: '../fonts/';

// bower:scss
@import "bower_components/bootstrap-sass/assets/stylesheets/_bootstrap.scss";
// endbower

Servidor web
Para empezar a trabajar modificando cdigo, lo mejor es levantar un servidor web:

gulp serve

Nos ofrece cambios en vivo (live reload).

Pgina de contactar
Aadimos un men responsive en la parte de arriba de la pgina

bs3-navbar-responsive + tab

175
Web con bootstrap y gulp

Como lo queremos fijo arriba, aadiremos la clase navbar-fixed-top


Como lo queremos centrado, cambiaremos la case container-fluid por container
El cdigo final queda as:

<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">


<div class="container">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" dat
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Mi web de cervezas</a>
</div>

<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse navbar-ex1-collapse">
<ul class="nav navbar-nav navbar-right">
<li class="active"><a href="#">Inicio</a></li>
<li><a href="#">Mis cervezas</a></li>
<li><a href="#">Contactar</a></li>
</ul>

</div><!-- /.navbar-collapse -->


</div>
</nav>

He aadido un formulario al body, los comandos que he utilizado son los siguientes:

bs3-input:text:h + tab
bs3-input:email:h + tab
bs3-input:submit:h + tab

Para que quede bien aadimos un container para el body (container o container-fluid) que
englobe al formulario (MAYS + CTRL + g en emmet, y escribimos .container).

Tambin aadimos un padding al body:

body {
padding-top: 70px;
}

Crear mi propio theme


Para empezar no me harn falta todos los import de css de bootstrap, as que me creo una copia
_bootstrap.scss en mi carpeta de styles, que ser el que utilice. Lo llamar _theme.less (ya que
al modificar Bootstrap voy a generar mi propio tema)

El main.scss de mi carpeta de estilos quedar as:

$icon-font-path: '../fonts/';
176
Web con bootstrap y gulp

// bower:scss
@import "_theme.scss";
// endbower

body {
padding-top: 70px;
}

Mi nuevo fichero _bootstrap.scss tendr estas rutas en sus import:

// Core variables and mixins


@import "bower_components/bootstrap-sass/assets/stylesheets/bootstrap/vari
@import "bower_components/bootstrap-sass/assets/stylesheets/bootstrap/mixi
...

Para cambiar el estilo de boostrap, lo mejor, en la medida de lo posible es utilizar sus variables:

Es el modo que han definido los creadores para hacer las modificaciones de forma
sencilla.
Observa que tambin podras hacer las modificaciones va web, pero sera ms costoso:
No siempre tienes claros los cambios
Hay pginas que te dejan ver los cambios en vivo mejorando la pgina
"Customize" del propio bootstrap.

Ejemplo de uso

Vamos a buscar una interfaz sin botones redondeados:

Miramos el fichero _buttons.scss que define los botones.


Vemos que hay un mixin que es el encargado del estilo redondeado:

@include button-size($padding-base-vertical, $padding-base-horizontal, $f

Comprobamos que efectivamente es el encargado, viendo el css que hay definido en el mixin
button-size:

// Button sizes
@mixin button-size($padding-vertical, $padding-horizontal, $font-size, $line-h
padding: $padding-vertical $padding-horizontal;
font-size: $font-size;
line-height: $line-height;
border-radius: $border-radius;
}

En el fichero de variables de Bootstrap vemos como la definen:

$btn-border-radius-base: $border-radius-base !default;

Aado en mi fichero _theme.scss la variable que quiero utilizar, en mi caso $border-radius-


base, ya que quiero que los input tampoco tengan los bordes redondeados:

//defino mis variables, las podra llevar a un fichero separado, si fueran


//no pasa nada porque se definan de nuevo posteriormente, ya que llevan el
$border-radius-base: 0px;
177
Web con bootstrap y gulp

// Core variables and mixins


@import "bower_components/bootstrap-sass/assets/stylesheets/bootstrap/vari
@import "bower_components/bootstrap-sass/assets/stylesheets/bootstrap/mixi
....

Aadir plugins
Vamos a buscar un plugin para hacer una validacin ms especfica:
Le podremos dar el css que nosotros quereamos, sin ser algo especfico del
navegador
Tendr mtodos adicionales para la validacin (adems de los que podamos definir
nosotros).

bower search validation


bower install jquery.validation --save

Lo "enganchamos" a nuestro sitio web mediante el comando:

gulp wiredep

En nuestro fichero main.js aadimos el cdigo necesario para cargar nuestro plugin con nuestro
formulario (al formulario le he aadido el id frmcontactar):

$('#frmcontactar').validate();

Comprobamos el funcionamiento mediante gulp serve


Si ya est terminado el proyecto podemos generar nuestro cdigo final mediante gulp build

178
React.js con material-ui

React.js con material-ui


React.js con material-ui
Rutas y arquitectura de la aplicacin
Utilizaremos un starter kit:
Hacemos un clone del proyecto e instalamos dependencias:

npm install

Instalamos react router:

npm i -S react-router

El cdigo que a continuacin utilizaremos est formateado sin acabar en ";". Por ello:

Configuraremos eslint de esta forma. Aadimos la regla en el fichero .eslintrc:

"semi": [2, "never"]

Corregiremos el cdigo presente:

node_modules/.bin/eslint --fix .

Ahora modificaremos nuestros ficheros fuente. En nuestro componente <App/> nos


encargaremos de renderizar nuestro enrutador (no deja de ser otro componente) que ser el que
se encargue de cargar las distintas vistas:

import React, { Component } from 'react'


import { Router, Route, browserHistory } from 'react-router'
import Index from './views/Index'
import Contactar from './views/Contactar'
import Cervezas from './views/Cervezas'

export default class App extends Component {


render() {
return (
<Router history={browserHistory}>
<Route path="/" component={Index}/>
<Route path="/cervezas" component={Cervezas}/>
<Route path="/contactar" component={Contactar}/>
</Router>
)
}
}

Las vistas sern de momento algo tal como:

import React, {Component} from 'react'

179
React.js con material-ui

export default class Cervezas extends Component {


render() {
return (
<h1>Mi lista de cervezas</h1>
)
}
}

Vamos a intentar hacer ahora rutas anidadas. En la ruta base, cargaremos una plantilla que ser
la encargada de colocar el men, header y footer para todas las pginas:

import React, { Component } from 'react'


import { Router, Route, browserHistory, IndexRoute } from 'react-router'
import Index from './views/Index'
import Contactar from './views/Contactar'
import Cervezas from './views/Cervezas'
import Template from './layout/Template'

export default class App extends Component {


render() {
return (
<Router history={browserHistory}>
<Route path='/' component={Template}>
/*observa que definimos IndexRoute, que ser la ruta por defecto
/*Todas las rutas siguientes estn anidadas dentro de template,
son hijas de la anterior y desde la template cargaremos la que c
<IndexRoute component={Index}/>
<Route path='cervezas' component={Cervezas}/>
<Route path='/contactar' component={Contactar}/>
</Route>
</Router>
)
}
}

Creo una carpeta llamada layout donde colocaremos el footer, header y resto de componentes
asociados a la plantilla. De momento la plantilla con el siguiente cdigo:

import React, {Component} from 'react'

export default class Template extends Component {


render() {
return (
<div>
<header><h1>Sitio web de mis cervezas</h1></header>
<main>{this.props.children}</main>
<footer>Realizado por juanda</footer>
</div>
)
}
}

Integracin con material-ui


180
React.js con material-ui

Lo primero que debemos hacer es instalar y configurar material-ui para el uso en nuestra
aplicacin:

npm i -S material-ui react-tap-event-plugin

En el fichero app.js:

import injectTapEventPlugin from 'react-tap-event-plugin';

// Needed for onTouchTap


// Check this repo:
// https://github.com/zilverline/react-tap-event-plugin
injectTapEventPlugin();

En el index.html:

<link href='https://fonts.googleapis.com/css?family=Roboto:400,300,500' re

Comprobamos si funciona o no, mediante un npm start y vemos que los warnings que nos han
salido en la instalacin hay que arreglarlos: ciertos errores de dependencias que nos obligan a
actualizar la versin de react y react-dom

Creo el componente Menu.js copiando cdigo de la web de Material-ui:

import React from 'react'


import Drawer from 'material-ui/Drawer'
import MenuItem from 'material-ui/MenuItem'
import RaisedButton from 'material-ui/RaisedButton'

export default class Menu extends React.Component {

constructor(props) {
super(props);
this.state = {open: false};
}

handleToggle = () => this.setState({open: !this.state.open});

render() {
return (
<div>
<RaisedButton
label="Toggle Drawer"
onTouchTap={this.handleToggle}
/>
<Drawer open={this.state.open}>
<MenuItem>Menu Item</MenuItem>
<MenuItem>Menu Item 2</MenuItem>
</Drawer>
</div>
)
}
}

181
React.js con material-ui

En la template lo tengo que llamar:

import React, {Component} from 'react'


import Menu from './Menu.js'

export default class Template extends Component {


render() {
return (
<div>
<header><h1>Sitio web de mis cervezas</h1></header>
<Menu/>
<main>{this.props.children}</main>
<footer>Realizado por juanda</footer>
</div>
)
}
}

Comprobamos que no funciona ya que para usar los componentes de Material-ui es necesario
utilizar un theme. Lo aadimos tal y como marca la documentacin, en el fichero App.js:

import React, { Component } from 'react'


import { Router, Route, browserHistory, IndexRoute } from 'react-router'
import Index from './views/Index'
import Contactar from './views/Contactar'
import Cervezas from './views/Cervezas'
import Template from './layout/Template'

import getMuiTheme from 'material-ui/styles/getMuiTheme'


import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'

import injectTapEventPlugin from 'react-tap-event-plugin'

// Needed for onTouchTap


// Check this repo:
// https://github.com/zilverline/react-tap-event-plugin
injectTapEventPlugin()

export default class App extends Component {


render() {
return (
<MuiThemeProvider muiTheme={getMuiTheme()}>
<Router history={browserHistory}>
<Route path='/' component={Template}>
/*observa que definimos IndexRoute, que ser la ruta por defecto*/
/*Todas las rutas siguientes estn anidadas dentro de template, es
son hijas de la anterior y desde la template cargaremos la que cor
<IndexRoute component={Index}/>
<Route path='cervezas' component={Cervezas}/>
<Route path='/contactar' component={Contactar}/>
</Route>
</Router>
</MuiThemeProvider>

182
React.js con material-ui

)
}
}

Si lo ejecutamos ahora veremos que funciona. Sin embargo el botn queda escondido detrs del
men. Lo podemos arreglar utilizando css directamente desde el JavaScript:

import React from 'react'


import Drawer from 'material-ui/Drawer'
import MenuItem from 'material-ui/MenuItem'
import RaisedButton from 'material-ui/RaisedButton'

const styles = {
container: {
width:'800px',
margin: '0 auto'
}
}

export default class Menu extends React.Component {

constructor(props) {
super(props);
this.state = {open: false};
}

handleToggle = () => this.setState({open: !this.state.open});

render() {
return (
<div style={styles.container}>
<RaisedButton
label="Toggle Drawer"
onTouchTap={this.handleToggle}
/>
<Drawer open={this.state.open}>
<MenuItem>Menu Item</MenuItem>
<MenuItem>Menu Item 2</MenuItem>
</Drawer>
</div>
)
}
}

Ms tareas
Podramos aadir otros componentes pero la tarea no deja de ser similar.

Quiz podramos utilizar un sistema de rejilla tipo Bootstrap para colocar los elementos y
ahorrarnos cdigo css o js. Una buena opcin sera http://flexboxgrid.com/.

183
React.js con material-ui

184

You might also like