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
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:
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:
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... ).
- 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.
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!