Archivo del blog

lunes, 11 de agosto de 2014

Un poquito de AngularJs

Con el auge de javascript en estos últimos años, me he aventurado a explorar mas allá de mi querido jquery que tantas alegrías me ha dado y me he decidido por Angular ya que se habla mucho de él.
Con esto no estoy dando de lado a mi jquery y luego hablaré de ello,pero primero una aproximación de lo que hace Angular (bajo mi punto de vista):

  • Aplica un patrón MVC para la parte de cliente ya que los comportamientos de las aplicaciones web se han hecho muy complejos.
  • Organiza el código javascript en módulos y tiene especial cuidado con los ámbitos de visibilidad.
  • Separa la capa de vistas (HTML) y utiliza templates para incorporar el contenido.
  • Utiliza atributos especiales en el html, llamados directivas, para vincular el javascript a un tag html.

Lo primero es bajarse el js de angular de su pagina oficial. Una vez que lo tenemos podemos empezar a trabajar.La verdad que hay documentación pero muy dispersa y la documentación oficial no es demasiado buena, pero siempre esta stackoverflow para ayudarnos.

En fin, he preparado un ejemplo, no muestro todo ni mucho menos, pero un poquito de como es la mecanica de AngularJs.



Paso 1 : La pagina index.html



Empezamos con un html muy básico, como vemos, hago referencia a los css al principio y, por recomendación últimamente de todos, los scripts al final.La linea marcada es el fichero de angular, ¿Porque no lo pongo el primero? os preguntareis, pues al parecer si tienes jquery y lo importas antes, lo utiliza para ciertas funciones, y si no utiliza una versión reducida, yo aparte le he metido un par de librerías mías.
Como vemos también, importamos un fichero llamado app.js, que es donde vamos a trabajar en javascript, por el momento sigamos viendo el html.

Si nos fijamos en la etiqueta body, tiene una propiedad llamada ng-app, que no es estándar de html, es una directiva de angularjs, que le indica a que modulo pertenece todo ese bloque, en este caso es el body con lo cual todo el cuerpo del html tiene acceso al modulo app, que es como el 'root'.Como hacemos esto? pues es el momento de ver nuestro fichero app.js:


Declaramos una variable para que contenga el modulo 'myapp', que tiene que coincidir con la etiqueta
ng-app que hemos visto anteriormente. Aquí ya lo tenemos registrado.

Hasta aqui solo hemos preparado el framework, vamos a añadir algo mas al fichero app.js:


Hemos creado nuestro controlador llamado 'HelloController', utilizamos la variable app creada anteriormente y accedemos a registrar el controlador.
Como vemos, este controlador tiene poco, con this creamos los objetos en el ámbito visible de este controlador, aquí creamos un objeto vacío llamado client y asignamos un objeto creado en el fichero models.js que vemos a continuación:


Lo he separado en otro fichero para que veamos como se pueden separar todos los elementos del MVC, es un array de objetos con 3 propiedades, nos va servir para pintar un formulario.

Volvamos al controlador, ya lo tenemos registrado en nuestro modulo, ahora lo queremos utilizar en nuestro html, ¿como hacemos esto? de la siguiente manera:


La capa 'divMain' tiene un tag llamado ng-controller, al que le asignamos el controlador 'HelloController' y le damos un alias como ctr con la palabra 'as'.
Ahora todo lo que se coloque centro de esta capa, tendrá acceso a las 2 variables que hemos declarado en el controlador anteriormente y a todo lo que declaremos dentro, como métodos u otras variables.
Vamos a crear algo mas en el html, vamos a conocer a otra directiva de angular:


Dentro de la capa 'divMain' hemos declarado la capa que tiene la clase 'row' y tiene un atributo llamado
ng-repeat. Este atributo repite este tag y su contenido como si fuese un bucle foreach.
Aquí vamos a utilizar uno de los objetos declarado en el controlador, que es el objeto forms, que esta en models.js y es un array de objetos, la forma de acceder es el alias del controlador y la variable declarada (ctr.frm). En el ng-repeat le estamos indicando que asigne a inp el valor de cada elemento de ctr.frm, con lo que si tenemos 3 elementos pintara 3 capas con clase 'row' que contienen una capa con la clase
'col-md-4'.
Hasta aquí no hemos hecho nada útil, pintar 3 capas vacías, a partir de aquí vamos a crearnos una custom directive:

2. Aplicando una custom directive

¿Que es una custom directive? pues una nueva etiqueta, atributo o clase que podemos utilizar en nuestro html, como las que hemos utilizado hasta ahora (ng-app, ng-repeat etc) pero personalizada para que se comporte como nosotros queremos.
Vamos a ver como lo hacemos, en primer lugar vamos a añadir mas codigo al app.js:


Vamos a explicarlo linea por linea:

Lo primero, como es habitual, cogemos nuestro objeto app y en este caso en vez de registrar un controlador, vamos a registrar una directiva con la función 'directive'. El nombre de nuestra directiva es el primer parámetro de la función, en este caso 'shInput', una nota importante, si el nombre es como en este caso una nomenclatura de mayúsculas y minúsculas, como html es case insensitive, angularjs te convierte shInput es sh-input como etiqueta.
El segundo parámetro es una función, que debe retornar un objeto con unas propiedades definidas:

  • restrict : Esta propiedad el objeto indica como queremos que funcione la directiva, es decir, si queremos que sea un elemento html , si queremos que sea una propiedad de un elemento html
    o si queremos que funcione como una clase css
    Puede tener 3 valores: A(tributo), E(lemento)y C(lase)
  • scope : Esta propiedad es un objeto que indica que parámetros se le deben pasar a nuestra directiva y la forma de interactuar con dichos parámetros.En este caso tenemos 2 parámetros obj y model, como vemos los asignamos con el prefijo '=', esto indica que es 2way-binding, es decir, que lo que se modifica en este objeto se refleja inmediatamente en todas las partes de la aplicación que utilicen este objeto.Si quisiéramos simplemente enviar un dato no relevante que se pueda modificar en la directiva se lo enviaríamos con el prefijo '@', eso le indica al parámetro que el ámbito del parámetro es local. (Es algo parecido a pasar por valor o pasar por referencia en C).
  • link : Es la función que se va a ejecutar al llamar a la etiqueta, a modo de render. En esta función  podemos manipular el DOM HTML gracias a los parámetros de entrada de la función $scope, element y attributes. El parámetro element es nuestra etiqueta, el root. El elemento element funciona como la función de jquery '$', de hecho la utiliza y si hemos importado jquery antes que angular funcionan todas las funciones de jquery (element.append(), element.find() etc... ).
Estas son las propiedades que escribo en el ejemplo pero hay otras propiedades que nos son de ayuda:

  • template : La propiedad template puede sustituir a la función link cuando la lógica es muy simple, por ejemplo pintar un label, en ese caso quitamos la función link y la sustituimos por : template=", esto nos pintaría un label cuando llamemos a la directiva.
  • templateUrl : Esta propiedad también puede sustituir a la función link, básicamente en esta propiedad le indicamos la ruta de un snippet html que tengamos en otro fichero, es decir llamamos a un html que tiene un trozo de codigo que es el que queremos insertar en la directiva, esta forma de implementación parece que es la que mas aconsejan, pero para lógicas complejas necesitaremos la función link.
Como vemos, esto es al gusto del programador, yo me siento cómodo manipulando el DOM y creando elementos dinámicamente, quizá otros desarrolladores prefieren tener todo organizado en templates html e ir llamando a esos ficheros, así si tienes que cambiar algo, solo cambias un fichero pequeño, en fin, hay muchos caminos.

La funcion link:

En la función link tenemos varias lineas de código que voy a explicar detalladamente.
La primera linea, si sabemos algo de jquery nos resultará familiar, element.html() inserta el html que le enviamos como parámetro dentro de nuestra directiva, dentro de element.html() he llamado a una función propia que me pinta una label y un input con los estilos de bootstrap, he llamado a esta función para que veamos como funcionan nuestros parámetros scope, enviados por referencia.
Nuestro ámbito es $scope, que es un parámetro de la función, en este ámbito están las 2 propiedades de scope que hemos declarado, y accedemos a dichos objetos con $scope.obj o $scope.model.
Los parámetros que requiere mi función para pintar los label y los input de bootstrap requiero el label, el id del input, un indicador para mostrar o no el botón de búsqueda y por ultimo el ng-model que le queremos aplicar.
El ng-model es una directiva de angular para indicarle al campo del formulario a que propiedad del modelo tiene que asignarle al valor, es una directiva muy util si trabajamos con formularios.
Hay un problema con la generación de elementos nuevos al DOM que llevan directivas angular, las asigna al elemento, pero no las interpreta, para este propósito tenemos la función $compile, que si nos fijamos, se le envía como parámetro a nuestra función de directiva, si no se la pasamos no podemos utilizarla ya que no es visible en este ámbito.
Esta función $compile(elemento)(scope), lo que hace es forzar a interpretar las directivas angular, y el html que genera no exactamente igual a lo que nosotros escribimos. Otra peculiaridad de esta función es que solo va a compilar el root del elemento pasado, no compilaría todo lo que haya dentro del elemento, yo en este caso como donde le aplico la directiva es un input, compilo el input nada mas.

Las lineas restantes son modificaciones de css aplicadas a los elementos que hemos creado, para que podamos comprobar que podemos modificar el DOM.
Por ultimo tengo una pequeña lógica, dependiendo de un campo de nuestro modelo, declarado en nuestro controlador y enviado como parámetro a la directiva, evaluamos si el campo es true o false y aplicamos un estilo o no en función del resultado, es una pequeña muestra de la lógica que se puede aplicar a la hora de pintar la directiva.

Con esto ya tenemos nuestra parte javascript lista para utilizarse, pero aun en el html no hemos llamado a esta directiva, así que tenemos que modificar el html:


Aquí esta nuestra parte final, lo que esta marcado en rojo es nuestra nueva y personalizada directiva, vamos a repasar el código escrito:

  • el ng-controller en primer lugar que lo tenemos envolviendo todo el código, así tendremos acceso a sus objetos y funciones
  • La siguiente linea es el ng-repeat, el cual itera el array frm dentro de nuestro controlador
  • Un div envolviendo nuestra custom directive
  • nuestra custom directive sh-input, que le enviamos el objeto iterado y el controlador para que tenga acceso a ambos objetos y pueda interactuar con ellos
  • La ultima parte del código es la prueba de que el two-way binding funciona con nuestro objeto, es una clase que dentro tiene una expresión de angularjs, los {{...}} inyectan el valor de la variable en el html. Cuando el valor del atributo cambie, se reflejara instantáneamente en la pantalla.
Con esto concluye el ejemplo, ahora veamos como se ve ejecutado:




Como vemos en el vídeo, tenemos 3 campos input en el formulario, tantos como tenemos en el modelo vinculado a través del controlador y vemos que el ng-model funciona correctamente al mostrar el texto en la capa inferior a la vez que escribimos en el input. Hay manera de validar los inputs en función de su contenido a través de html5 y sus nuevos tipos de inputs.

Este ha sido un ejemplo muy básico, y un acercamiento a AngularJs, pero hay mucho mas que no he explicado, como los servicios y llamadas al servidor, que lo explicare en otro capitulo basándome en este ejemplo.

Un saludo!



viernes, 20 de febrero de 2009

Crear un Bean a partir de JSON y viceversa

Buenas a todos, esta es mi primera publicación y bueno, os hago una intro, soy un programador de 28 años y me gustaria compartir algunas cosillas que he aprendido, seguramente de alguno de vosotros y como no me gusta la ciberAvaricia pues dejare mi legado por si a alguien le puede ayudar en un momento dado, porque a mi me ha pasado y he encontrado mucha ayuda gracias a toda la comunidad.

Bueno, voy a hablaros de algo que aprendi hace no mucho y me parecio interesante, como pasar de un Bean en java a un objeto JSON en javascript.
En el ambito de las aplicaciones Web (J2EE, JEE o como querais) en los MVC(modelo - vista - controlador) lo mas habitual es enviar los datos desde el formulario del navegador usando la propiedad action y recogerlo con un Request, pero a mi me gusta mucho la idea de Ajax ya que odio tener que hacer un reenvio hacia la misma pagina ademas de perder rendimiento, tampoco recomiendo Ajax para todo, pero me parece muy util para enviar información de un formulario hacia el servidor.

Un compañero mio hace ya tiempo me hablo de la libreria de javascript jQuery que muchos conocen y los que no, yo se la recomiendo ya que te facilita una barbaridad escribir javascript ademas de tener métodos para hacer llamadas al servidor con Ajax y no tener que utilizar tu el XmlHttpRequest directamente que es un poco engorroso.
la forma de hacerlo es la siguiente :
$.ajax({ 
type: "POST",

url: "../index",

data: "nombre=Shoe
011",
success: function(msg){

alert( "Retorno del servidor: " + msg );

}

});


Como vemos, la llamada a Ajax es muy sencilla, tenemos mas opciones ademas de las
que yo indico en el ejemplo, pero describire estas ya que son las mas básicas:
  • type : es el tipo de envio, GET/POST
  • url : es la URL de la página o clase java que se quiere llamar, en este caso es una clase.
  • data : son los datos que se desea enviar, Java los interpretara como un String
  • success : es un callback, una funcion que realizara una tarea cuando termine la recepción en este caso mostrara un alert, y fijemonos bien que el parámetro de esta funcion sera el retorno desde el servidor de vuelta a la página, si enviamos algo desde el servidor, se almacenará en esta variable, en este caso la función muestra un alert con la respuesta del servidor.
Hasta aqui es todo relativamente fácil, ahora bien, compliquemos la cosa, pongamos que yo utilizo Beans por cada tabla SQL para que la información viaje bien estructurada:




Este es el esquema de uno de mis Bean, tiene 3 propiedades y sus metodos getters y setters.







Pues quiero que haya un formulario en la pagina jsp para poder registrarte como nuevo usuario donde el usuario introduce su nombre su password y una identificación, 3 campos simples que los tenemos en el jsp y queremos agregarlos a la base de datos pero no queremos recargar la página ni tener que declarar en el jsp ningun useBean o ningun objeto, o lo que yo pretendo, separar totalmente el codigo java, el codigo HTML y el codigo javascript.

Entra en juego algo que lleva muchos años creado pero yo no sabia de su existencia hasta hace relativamente poco y es la notación JSON, que es una notación para Javascript(no nos confundamos, esto no se aplica a Java, solo a JS ) la cual nos permite crear un objeto a partir de una cadena de texto con un formato determinado:

var ObjJSON = {"Lista": [
{"nombre": "Pepe", "edad": "20"},
{"nombre": "Juan", "edad": "22"},
{"nombre": "Pedro", "edad": "27"},
]
};
Este fragmento crearia un objeto con nombre ObjJSON y seria una lista con 2 columnas, nombre y edad.

ObjJSON.Lista[0].nombre
ObjJSON.Lista[0].edad


Con este fragmento que muestro puedo recoger el valor de nombre y edad del primer elemento de la lista, el rersultado sería Pepe y 20 respectivamente.

Ahora bien, ¿como podemos formar un objeto de este tipo a base de texto? puedes utilizar el metodo nativo de JS eval(val) de esta forma :
var txtJSON = "{'nombre' : 'shoe011','edad':'28'}";
var objJSON = eval('('+ txtJSON +')');
Pero no se recomienda utilizar eval si los datos que se envian pueden ser de riesgo(Puede colarse SQL inyectado por ejemplo) asi que recomiendo una extension de jQuery, el jQUery.json que tiene varios métodos seguros para evaluar textos y convertirlos en objeto y viceversa, el link es a la documentacion, es muy escueta pero mas que suficiente.

Bueno con esto sabemos ya crear objetos con notacion JSON, en nuestro caso siempre tendremos que mandar texto hacia el servidor y alli interpretarlo, entramos en el lado sel servidor.

Ya estamos en la parte java y quiza esto sea lo mas rollete, el bajarte todas las librerias que hacen falta, son todas opensource, la mayoria de Apache fundation.
Voy a hacer una lista con los links:
Se necesitan todos los jars como librerias de la aplicacion, son muy ligeras y muy potentes y ademas opensource, que mas queremos.Ahora pongo el codigo del servlet, este servlet es heredado de un servlet padre que ejecuta el método procesar y envia texto hacia el navegador de esta manera:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
this.request=request;
this.response=response;
response.getWriter().write(procesar());
}


Simplemente en vez de hacer una redireccion hacia una URL, enviamos lo que nos devuelve el método procesar que desarrollo a continuación:

protected String procesar() {
JSONObject jsonObj = JSONObject.fromObject(request.getParameter("data").toString());
BeanAlbums bean = (BeanAlbums) JSONObject.toBean(jsonObj, BeanAlbums.class);

ShConnAlbums connAlbums = new ShConnAlbums();
Connection con = connAlbums.conn;
connAlbums.add((com.mysql.jdbc.Connection) con, bean);

return "";
}

Aqui aparecen cosas especificas de la libreria Json-lib, en primer lugar el objeto JSONObject recoge el parámetro que le enviamos desde JS en formato texto de esta manera:

$.ajax({
type: "POST",
url: "../MapAlbum",
data: "data="+v,
success: function(msg){
}
});

Como vemos en la propiedad 'data' formamos un String con data + v, donde v sera la cadena JSON en modo texto, es una aclaración ya que para poder coger el objeto completo debemos asignarlo asi, de otra forma cogeria las propiedades del objeto JSON por separado y no como un solo objeto, que es lo que nosotros queremos.

BeanAlbums bean = (BeanAlbums) JSONObject.toBean(jsonObj, BeanAlbums.class);

Esta linea es la que convierte nuestro objeto JSON en un Bean.El bean debe tener la misma estructura que el objeto JSON, de lo contrario saltaria una excepción.
Vemos que hacemos un Cast a mi Bean (BeanAlbums) y el método .toBean que tiene 2 parámetros, el primero es el objeto JSON que acabamos de crear a partir del request y el segundo es el objeto class de la clase a la que queremos convertir, en este caso BeanAlbums.class
y en este momento ya disponemos de un bean java relleno con los datos deseados, quiza en el ejemplo no parezca gran cosa,pero si se envian gran cantidad de datos de un formulario te ahorras un grueso importante con una sola instruccion.
Una vez tienes el Bean puedes hacer lo que quieras, como hago yo, agregar un registro a la base de datos.

Creo que es algo a tomar en cuenta ya que la conversion es espectacular y muy rápida.

Espero que os haya gustado...
Un saludo!!!