Let's Code!

Archivo para May, 2013

Creando una Directiva para propiedades tipo Fecha y Hora.(II)

5. CREANDO NUESTRA VISTA.

Nuestra vista será codigo HTML, mostrando un control Select por cada una de las partes de nuestra Fecha, en cada uno de estos controles selects usaremos nuestra directiva del tipo atributo e indicaremos la propiedad del modelo que vamos a enlazar, cuyo nombre es indicado en el atributo cp-date y además la parte de nuestra fecha que nuestra directiva se encargará de refrescar en la UI, esto es indicado en el atributo part.

<div>
	<select cp-date="myDate" part="month">
		<option disabled selected value="">MONTH</option>
		<option ng-repeat="m in months" value="{{m}}">{{m}}</option>
	</select>
	<select cp-date="myDate" part="day">
		<option disabled selected value="">DAY</option>
		<option ng-repeat="d in days" value="{{d}}">{{d}}</option>
	</select>
	<select cp-date="myDate" part="year">
		<option disabled selected value="">YEAR</option>
		<option ng-repeat="y in years" value="{{y}}">{{y}}</option>
	</select>
	<br/>
	<select cp-date="myDate" part="hour">
		<option disabled selected value="">HOUR</option>
		<option ng-repeat="m in hours" value="{{m}}">{{m}}</option>
	</select> _:_
	<select cp-date="myDate" part="minute">
		<option disabled selected value="">MINUTES</option>
		<option ng-repeat="d in minutes" value="{{d}}">{{d}}</option>
	</select>__
	<select cp-date="myDate" part="period">
		<option selected value="AM">AM</option>
		<option selected value="PM">PM</option>
	</select>
	<br/>
	Mi Modelo es: {{myDate}}
</div>

6. CREANDO NUESTRA DIRECTIVA.

Nuestra directiva, se encargará de observar la propiedad del modelo, cuyo nombre es indicado en el atributo cp-date y se encargará de refrescar en la UI la parte indicada en el atributo part.

jFaqDirectives.directive('cpDate', ['$log','$parse', function (log, parse) {
    return function(scope, elem, attrs){
		var _date = new Date();
		var _yearZero = 0;

		scope.$watch(attrs.cpDate, function(value) {
			if(value) {
				_date = new Date(value);
				log.info('date changed = ' + _date);
				updateUI();
			}
		});

		function populateYears() {
			var currentYear = new Date().getFullYear();
			_yearZero = currentYear;
			scope.years = [];
			for(var i= currentYear; i&gt; currentYear - 20 ; i--) {
				scope.years.push(i);
			}
		}

		function populateMonths() {
			scope.months = ['January','February','March','April','May','June','July','August','September','October','November','December'];
		}

		function populateDays() {
			var daysInMonth = new Date(_date.getFullYear(), _date.getMonth() + 1, 0).getDate();
			scope.days = [];
			for(var i= 1; i &lt;= daysInMonth; i++) {
				scope.days.push(i);
			}
		}

		function populateHours() {
			scope.hours = [12,1,2,3,4,5,6,7,8,9,10,11];
		}

		function populateMinutes() {
			scope.minutes = [];
			for(var i= 0; i &lt;= 59; i++) {
				scope.minutes.push(i);
			}
		}

		function updateUI() {
			//TODO: usar Jquery
			if(attrs.part == 'month') {
				var m = _date.getMonth();
				//elem.val(scope.months[m]);
				elem.children()[m+1].selected = true;

			} else if(attrs.part == 'day') {
				var m = _date.getDate();
				//elem.val(m);
				elem.children()[m].selected = true;

			} else if(attrs.part == 'year') {
				var y = _date.getFullYear();
				var index = _yearZero - y + 1;
				//elem.val(m);
				if(index &gt;= 0) {
					elem.children()[index].selected = true;
				}

			} else if(attrs.part == 'hour') {
				var m = _date.getHours();
				log.info('hours ' + m);
				if(m &gt; 11) m = m - 12;
				elem.children()[m + 1].selected = true;

			} else if(attrs.part == 'minute') {
				var m = _date.getMinutes();
				elem.children()[m + 1].selected = true;

			} else if(attrs.part == 'period') {
				var m = _date.getHours();
				if(m &gt; 11) {
					elem.children()[1].selected = true;
				}else {
					elem.children()[0].selected = true;
				}
			}
		}

		function getMonthIndex(name) {
			for(var i=0; i&lt; scope.months.length; i++) {
				if(scope.months[i] == name) {
					return i;
				}
			}
			return 0;
		}

		function bindEvents() {
			//TODO: usar Jquery
			if(attrs.part == 'month') {
				elem.bind('change', function() {
					_date.setMonth( getMonthIndex(this.value) );
					log.info(this.value);
					refreshModel();
				});

			} else if(attrs.part == 'day') {
				elem.bind('change', function() {
					_date.setDate(this.value);
					log.info(this.value);
					refreshModel();
				});
			} else if(attrs.part == 'year') {
				elem.bind('change', function() {
					_date.setYear(this.value);
					log.info(this.value);
					refreshModel();
				});
			}  else if(attrs.part == 'hour') {
				elem.bind('change', function() {
					_date.setHours(this.value);
					log.info(this.value);
					refreshModel();
				});

			} else if(attrs.part == 'minute') {
				elem.bind('change', function() {
					_date.setMinutes(this.value);
					log.info(this.value);
					refreshModel();
				});

			} else if(attrs.part == 'period') {
				elem.bind('change', function() {
					if(this.value == 'AM') {
						if(_date.getHours() &gt;= 12) {
							_date.setHours(_date.getHours() - 12);
						}
					}else {
						var h = _date.getHours();
						if(h != 12) {
							_date.setHours(h + 12);
						}
					}
					log.info(this.value);
					refreshModel();
				});
			}

		}

		function initialize() {
			populateYears();
			populateMonths();
			populateDays();
			populateHours();
			populateMinutes();
			bindEvents();
		}

		function refreshModel() {

			var newValue = _date;
			log.info('refreshModel to ' + _date);
                        //Esto es para que nuestro scope se entere del cambio.
			var parsed = parse(attrs.cpDate);
			scope.$apply(function() {
				parsed.assign(scope, newValue);
			});
		}

		initialize();
    };
}]);

7. PROBANDO NUESTRA DIRECTIVA.

Ahora si, lanzamos nuestro página en localhost y accedemos a nuestra página /date. La aplicación nos debe mostrar la fecha inicial colocada en el método initialize de nuestro controlador. Y podemos interactuar con los controles select, vemos que al cambiar cualquier item, nuestro modelo es actualizado y mostrado debajo de los controles select.

date

Hasta la próxima!!

Creando una Directiva para propiedades tipo Fecha y Hora.

1. CUAL ES LA IDEA?.

El objetivo de este post es crear un control html que será enlazado a una propiedad del tipo Fecha y Hora de nuestro modelo. Si bien es cierto que hay muchos controles ya implementados en el mercado, el objetivo de este post es implementar un control simple, extendiendo nuestro lenguaje HTML a través de la implementación de  Directivas en angularJs… bien, como siempre manos a la obra.

2. EXTENDIENDO NUESTRO HTML.

Definiremos nuestra solución como un par de atributos más del control HTML Select <Select>, el primer atributo nos dirá cuál es la propiedad del tipo Date dentro de nuestro modelo, mientras que el segundo atributo nos dirá que parte de la Fecha queremos controlar. Las partes que contemplaremos en esta solución son las siguientes: month, day, year, hour, minute y period.

La implementación, como mencionamos anteriormente, la haremos construyendo una directiva del tipo atributo en angularJs.

3. AGREGANDO EL CONTROLADOR A NUESTRO ROUTER.

Como siempre empezamos direccionando nuestro request a una vista y controlador particular, dentro de nuestro archivo app.js.

var miModulo = angular.module('miModulo',['jFaq.services','jFaq.directives'])
.config(['$routeProvider', function ($routeProvider) {
	$routeProvider
		.when('/date', {controller: 'dateController', templateUrl: 'views/fecha.html'})
		.otherwise({redirectTo:'/'});
}]);

4. CREANDO NUESTRO CONTROLADOR.

Nuestro controlador contendra nuestro modelo, el cuál consta de una variable tipo Date. Además definiremos una función de inicialización de nuestro modelo, la cuál se encargará de cambiar nuestro modelo a una fecha determinada. En este controlador tambien definiremos un conjunto de arrays necesarios por la directiva.

var dateController = miModulo.controller('dateController', function($scope, $window, $log){

	$scope.myDate = new Date();
	//propiedades usadas por la directiva.
	$scope.months = [];
	$scope.years = [];
	$scope.days = [];
	$scope.hours = [];
	$scope.minutes = [];
	//
	$scope.initalize = function() {
		$scope.myDate = new Date(2012, 0, 22);
		$scope.myDate.setHours(6);
		$scope.myDate.setMinutes(30);
		$log.info('date initialized = ' + $scope.myDate);
	};

	$scope.initalize();
});

Creando una simple sala de chat (IV)

9. Creando nuestro simple protocolo de mensajes.

Antes de empezar a codear la parte cliente de la conexion, necesitamos definir la estructura de nuestro mensaje. Para nuestro caso particular, necesitamos basicamente dos cosa: el nombre de usuario y el texto que envia. Para este caso particular, la forma mas sencilla de implementar esta estructura es la siguiente:

Mensaje = [ nombre_usuario + delimitador + texto_mensaje ]

De esta forma podemos obtener quien envio el mensaje y cual es el mensaje que envio. Nuestro delimitador debera ser una secuencia especial de caracteres de modo que no podamos confundir el nombre del usuario con el texto del mensaje.

Ahora si, estamos listos para implementar nuestro cliente.

10. Creando el socket cliente.

Como vimos anteriormente en nuestra vista chatroom.jade estamos incluyendo el archivo javascript client.js, este archivo contendra el codigo necesario para crear nuestro objeto socket cliente, luego usar este objeto para abrir una conexion al server que nos permitira enviar y recibir mensajes. El archivo contiene el siguiente codigo:

client.js

var username = '';
var iosocket ;
var delimitador = &quot;&lt;.&gt;&quot;;

var hola = function() {
  alert(username);
};

var enviarMsj = function() {
  var text = $('#txtMensaje').val();
  showMensaje(username, text);
  enviar2Server(text);
  $('#txtMensaje').val('');
};

var showMensaje = function(name, text) {
  var div = document.createElement('blockquote');
  div.className = 'example-right';
  var p = document.createElement('p');
  var node = document.createTextNode(text);
  p.appendChild(node);

  //var username = 'Jhon';
  var pname = document.createElement('p');
  pname.className = 'name';
  var nodename = document.createTextNode(name + ':');
  pname.appendChild(nodename);

  div.appendChild(pname);
  div.appendChild(p);

  var innerScroll = $('#innerScroll');
  innerScroll.append(div);

  innerScroll.scrollTop(9999999);
};

$(function(){
  username = $('#txtUserName').val();
  iosocket = io.connect();

  iosocket.on('connect', function () {
      $('#estado').html('&lt;li&gt;Conectado&lt;/li&gt;');

      iosocket.on('message', function(message) {
	 var array = message.split(delimitador);
	 var user = array[0];
	 var text = array[1];
	 showMensaje(user, text);
      });

      iosocket.on('disconnect', function() {
	  $('#estado').html('&lt;li&gt;Disconnected&lt;/li&gt;');
      });
  });

  $('#txtMensaje').keypress(function(event) {
      if(event.which == 13) {
	  event.preventDefault();
	  enviarMsj();
      }
  });

  //hola();
});

var enviar2Server = function (text) {
  var mensaje = username + delimitador + text;
  iosocket.send(mensaje);
};

Como podemos observar, hacemos uso de dos modulos particulares: el primer modulo es el socket client que nos brinda acceso a los objetos Socket, el cual se ubica en el archivo socket.io/scoket.io.js, que es creado por el modulo Socket.io de nodeJs. El segundo es jQuery que nos sirve para acceder a la UI y generar los delegados de eventos del DOM.

11. Enjoy!

Ejecutamos la aplicacion, para ello vamos a una consola y escribimos el siguiente comando dentro de nuestro directorio principal en donde se encuentra ubicado nuestro codigo:

$ node app.js

y veremos algo como:

   info  - socket.io started
Express server listening on port 3000

Ahora si ya podemos testear la aplicacion, vamos a nuestro explorador preferido (Evita usar Internet Explorer), y vamos a http://localhost:3000/ , ingresamos nuestro nombre de usuario e ingresamos a la sala de chat. Puedes abrir un segundo explorador y entrar con un usuario diferente para que puedas probar el chat.

Lo interesante es que a la vez hemos hecho una aplicacion que aplica el concepto de responsive application, es decir si accedes a la aplicacion desde el navegador en un smartphone, veras que funciona igual!.

Espero se hayan divertido una vez mas, con nodeJs puedes hacer cosas muy interesantes, asi que solo queda practicar un poco mas.

Les dejo la aplicacion desplegada aqui: http://quiet-plateau-4229.herokuapp.com/

Creando una simple sala de chat (III).

7. Creando nuestra hoja de estilos.

Nuestra hoja de estilos, ubicado dentro de nuestro directorio pubic/stylesheets/ luce de la siguiente manera:

main.css

body {
  font: 1em/1.4 Cambria,Georgia,sans-serif;
}

.outer {
  width: 100%;
}

.content {
  border-style: solid;
  border-width: 1px;
  border-color:blue;
  background-color: cyan;
  text-align: center;
  width: 50%;
  margin: 0 auto;
}

.texto {
  display:block;
  font-color: green;
  font-weight: bold;
}

.boton {
  weight: 200px;
  display: block;
  background-color: #FF9900;
  border-style: solid;
  border-width: 1px;
  border-color: #FF0000;
  margin: 0 auto;
}

.example-right {
  position:relative;
  padding:1px 10px;
  margin:5;
  color:#fff;
  background:#5a8f00; /* default background for browsers without gradient support */
  /* css3 */
  background:-webkit-gradient(linear, 0 0, 0 100%, from(#b8db29), to(#5a8f00));
  background:-moz-linear-gradient(#b8db29, #5a8f00);
  background:-o-linear-gradient(#b8db29, #5a8f00);
  background:linear-gradient(#b8db29, #5a8f00);
  -webkit-border-radius:10px;
  -moz-border-radius:10px;
  border-radius:10px;
  margin-right:40px;
}

/* display of quote author (alternatively use a class on the element following the blockquote) * /
.example-right + p {margin:15px 0 2em 85px; font-style:italic;}  */

.example-right:after {
  content:"";
  position:absolute;
  bottom:-20px; /* value = - border-top-width - border-bottom-width */
  left:50px; /* controls horizontal position */
  border-width:20px 0 0 20px; /* vary these values to change the angle of the vertex */
  border-style:solid;
  border-color:#5a8f00 transparent;
  /* reduce the damage in FF3.0 */
  display:block;
  width:0;
   top:16px;
	right:-40px; /* value = - border-left-width - border-right-width */
	bottom:auto;
    left:auto;
	border-width:15px 0 0 40px; /* vary these values to change the angle of the vertex */
	border-color:transparent #5a8f00 ;
}

/* creates the triangle */
.NOexample-right:after {
	content:"";
	position:absolute;
	bottom:-50px;
	left:50px;
	border-width:0 20px 50px 0px;
	border-style:solid;
	border-color:transparent #5a8f00;
    /* reduce the damage in FF3.0 */
    display:block;
    width:0;

}

blockquote {
    margin:1em 0;
}

blockquote p {
    margin-top:1;
    margin-left:5;
    font-size:14px;
    word-wrap: break-word;
}

blockquote p.name{
    margin:2;
    font-size:11px;
    word-wrap: break-word;
    font-weight:bold;
    color:blue;
}

.container {
  width: 400px;
  height:600px;
  /*border-style:solid;
  border-color:blue;
  border-width:1px;*/
  margin: 0 auto;
}

.innerScroll {
  width: 400px;
  height:570px;
  border-style:solid;
  border-color:black;
  border-width:1px;
  overflow-y:auto;
  overflow-x:hidden;
}

#txtMensaje {
  max-height:25px;
  width:300px;
}

#btnEnviar {
  width: 95px;
  height: 25px;

}

8. Modificando nuestro archivo app.js.

Nuestro archivo principal, en donde nos encargamos de crear nuestro servidor y nuestro socket, es el archivo app.js, en donde estaremos incluyendo los mòdulos necesarios e implementando el envìo y recepciòn de mensajes.

app.js


/**
 * Module dependencies.
 */

var express = require('express')
  , routes = require('./routes')
  , user = require('./routes/user')
  , http = require('http')
  , path = require('path')
  , io = require('socket.io');

var delimitador = "<.>";

var app = express();

// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
  app.use(require('stylus').middleware(__dirname + '/public'));
app.use(express.static(path.join(__dirname, 'public')));

// development only
if ('development' == app.get('env')) {
  app.use(express.errorHandler());
}

app.get('/', routes.index);
app.get('/users', user.list);
app.get('/about', function(req, res){
  res.render('about', { title:'Acerca De' });
});

app.post('/chatroom', function(req, res){
  var name = req.param('userName', null);  // second parameter is default
  //console.log('userName = ' + name);
  res.render('chatroom', { title:'chatroom', username: name });
});

var myApp = http.createServer(app);

myApp.listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

var onConnection = function (socket) {
    socket.on('message', function(msg) {
      onMessage(msg, socket);
    });
};

var onMessage = function (msg, socket) {
    //console.log('Message Received: ', msg);
    socket.broadcast.emit('message', msg);
    //console.log('Message Emitted: ', msg);
};

var sio = io.listen(myApp);
sio.on('connection', onConnection);

Creando una simple sala de chat (II).

5. Creando nuestra aplicación.

Una vez instalados node.js, npm y express.js, lo siguiente es crear nuestra aplicación. Para ello ejecutamos en una consola el siguiente comando:

$ express -c stylus expresschat

El uso del atributo -c indica a express que nosotros queremos utilizar stylus como renderizador de nuestro css. Mientras que expresschat es el nombre de nuestra aplicación.

Luego ejecutamos el sguiente comando:

$ cd expresschat && npm install

Con esto ya temenos creada nuestra estructura, por defecto express creará dos o tres vistas, llamadas index.jade y users.jade.

Nuestra aplicación hará uso de broadcasting basado en web sockets, para poder acceder a estos web sockets, existe una herramienta implementada en node.js llamada Socket.io, la cual debemos agregar como dependencia a nuestra aplicación. Para hacer esto ejecutamos el siguiente comando.

$ npm install socket.io

Bien ahora si nos damos cuenta, Express creo un archivo llamado package.json, en nuestro directorio raíz. Antes de empezar tenemos que editarlo en orden de agregar nuestra dependencia a socket.io. El archivo final debe lucir como se muestra a continuación.

{ "name": "application-name",
  "version": "0.0.1",
  "private": true,
  "scripts": {
     "start": "node app.js"
   },
  "dependencies": {
     "express": "3.2.4",
     "socket.io": "~0.9.6",
     "jade": "*",
     "stylus": "*"
   },
   "engines": {
     "node": "0.8.x",
     "npm": "1.2.x"
   }
}

6. Creando nuestras vistas.

Express.js es agnóstico al tipo de lenguaje que uses al momento de crear un template, para este caso usaremos el motor de plantillas Jade, te darás cuenta luego que es sencillo de usar.

A parte de las vistas generadas por defecto por Express, ubicadas en la carpeta views. Crearemos dos vistas principales, que se muestran a continuación:

chatroom.jade

doctype 5
html
  head
    title= title
    link(rel="stylesheet", href="/stylesheets/main.css")
    script(src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js")
    script(src="/socket.io/socket.io.js")
    script(src="/javascripts/client.js")
  body
   input(id="txtUserName", type="hidden", value=username)
   div(class="container")
    div(id="estado")
    div(id="innerScroll", class="innerScroll")
    input(id="txtMensaje", type="text", value="", placeholder="mensaje")
    input(id="btnEnviar", type="button", value="Enviar", onclick="enviarMsj();")
   

index.jade

extends layout

block content
  div(class="outer")
   div(class="content")
    form(action="/chatroom", method="POST", name="user")
     span(class="texto") Ingresa tu nick:
     input(type="text", placeholder="nick name", name="userName", value="", class="")
     input(type="submit", value="Empezar Chat", class="boton")

Además modificaremos nuestro archivo base denominado

layout.jade

doctype 5
html
  head
    title= title
    link(rel='stylesheet', href='/stylesheets/main.css')
  body
    block content

Creando una simple sala de chat.

1. Creando una sala de chat.

Lo que se describe a continuación es la implementación de una sala de chat pública, simple y sencilla, en la que un usuario puede ingresar su nombre y empezar a chatear con otros usuarios. Debido a efectos de tiempo, no se realizarán validaciones sobre los mensajes, de modo que cualquiera podría romper la aplicación. La idea de este tutorial es poder conocer node.js y algo de la tecnología conocida como WebSockects implementada en node.js con el módulo Socket.io.

Asi que manos a la obra.

2. Qué es node.js?

Node.js es una plataforma desarrollada en javascript bajo el entorno de ejecución de Chrome, que es usada del lado del servidor, para la creación rápida de sistemas web escalables. Esta plataforma usa 100% javascript y se basa en una arquitectura basada en eventos de entrada y salida asíncrona y  no bloqueante. Con node.js podras crear servidores http, servidores ftp o servidores tcp, sin el uso de otras herramientas como Apache. Si te gusta javascript, esto es para tí.

3. Instalando node.js en Ubuntu?

Para instalar node.js en Ubuntu, hay muchos tutoriales que pueden seguir, e incluso para obtener y compilar la última versión de node.js en sus sistemas.

Aqui les dejo los pasos obtenidos de esta página. (Es mejor instalarlos como root para poder tenerlos de manera global dentro de linux)

$ sudo apt-get update
$ sudo apt-get install git-core curl build-essential
$ sudo apt-get install openssl libssl-dev
$ git clone https://github.com/joyent/node.git && cd node
$ ./configure
$ make
$ sudo make install
$ echo 'export NODE_PATH=/path_to/node' >> ~/.bashrc
$ echo 'export PATH=$PATH:/path_to/node' >> ~/.bashrc
$ source ~/.bashrc
$ node -v

4. Instalando Express.js en Ubuntu?

Express.js es un light-weight application framework que nos facilita la creación de aplicaciones web bajo la arquitectura MVC. Con este framework tu puedes manejar de manera fácil los enrutadores, además puedes usar distintos lenguajes para generar plantillas como ejs, jade, etc.

Para la instalación de Express, una vez instalado node.js, basta con ejecutar el siguiente comando.

$ npm install -g express

Creando una FAQ page con angularJS (V)

6. Extendiendo nuestro HTML con la Directiva.

Como ya vimos, nuestra vista está yendo a usar un componente nuevo para renderizar nuestras preguntas y respuestas. Este componente es una extensión del lenguaje markup y es implementado a través de una Directiva en angularJs.

'use strict';
/* jFaq Directives */

var jFaqDirectives = angular.module('jFaq.directives', []);

jFaqDirectives.value('version', '0.1');

jFaqDirectives.directive('parse', ['$compile', function (compile) {
    return {
        restrict: 'E',
		replace: true,
        transclude: true,
        scope: {
            texto: '@texto',
			myclass: '@myclass'
        },
        link:function (scope, element, attrs) {
			attrs.$observe('texto', function(value) {
				if (value) {
					var str = value.replace(/&amp;lt;/g, '&lt;').replace(/&amp;gt;/g, '&gt;');
					var htmlText = '&lt;div class=&quot;'+ attrs.myclass +'&quot;&gt;' + str +'&lt;/div&gt;';
					var e = angular.element(htmlText);
					compile(e.contents())(scope);
					element.replaceWith(e);
				}
			});
        }
    };
}]);

7. Recursos adicionales antes de lanzar la aplicación.

Vista auto.html.

<div class="form">
	<div class="header">Datos de mi Auto:</div>
	<div>
	Marca de mi auto: <input type='text' ng-model="miAuto.marca" /><br/>
	Modelo de mi auto: <input type='text' ng-model="miAuto.modelo" /><br/>
	Matricula?: <input type='checkbox' ng-model="miAuto.tieneMatricula" disabled="true" /><br/>
	</div>
</div>
<hr/>
<div class="view">
	<div class="header">Mi Auto:</div>
	<div>
	Marca de mi auto: {{miAuto.marca}}<br/>
	Modelo de mi auto: {{miAuto.modelo}}<br/>
		<div ng-show="miAuto.matricula">
		Matricula Creada: {{miAuto.matricula}}<br/>
		</div>
	</div>
	<hr/>
	<div>
		Ciudad :<input type="text" ng-model="miAuto.ciudad" />
		<input type="button" value="Crear Matricula" ng-click="obtenerMatricula()" />
	</div>
</div>

Estilos main.css.

html, body {
	text-align:center;
}

#wrapper {
	margin: 0 auto;
	width: 800px;
	text-align:left;
}

.menu {
	text-align:center;
	background-color: green;
	font-weight: bold;
	font-size: 30px;
}

.menu a{
	color: yellow;
}

.header {

	font-weight: bold;
	font-size: 18px;
}

.pregunta {
	display:block;
	color:red;
	font-weight: bold;
	font-size: 18px;
	margin-top:10px;
}
.respuesta {
	font-size: 14px;
}

8. Eureka!

Aplicacion Final

Espero se hayan divertido!

Creando una FAQ page con angularJS (IV)

5. Definiendo el Controlador.

Nuestro archivo controllers.js contendrá los controladores para nuestras vistas, en este caso, para nuestra vista de las preguntas frecuentes que definiremos luego. Este controlador se llama faqController y hace uso del servicio para obtener las entradas del archivo XML y mantenerlo en un array denominado jsonEntries.

//Controlador de la vista auto.(No considerada en este tutorial)
var autoController = miModulo.controller('autoController', function($scope){
	//intercatuar con el modelo: miAuto
	//este modelo y funciones pueden ser accedidos directamente
	//desde la vista.

	$scope.miAuto = {};
	$scope.miAuto.marca = "";
	$scope.miAuto.modelo = "";
	$scope.miAuto.ciudad = "";

	$scope.obtenerMatricula = function() {
		if($scope.miAuto.ciudad) {
			$scope.miAuto.matricula = "Matricula Obtenida en " + $scope.miAuto.ciudad;
			$scope.miAuto.tieneMatricula = true;
		}
	};
});

/**
 * FaqController: Controlador de la vista de preguntas frecuentes.
 * @constructor
 */
var faqController = miModulo.controller('faqController', function($scope, $http, $log, jFaqService) {

	$scope.jsonEntries = [];

	$scope.renderEntries = function() {
		var xmlUrl = 'data/data.xml';
		jFaqService.getJsonEntries(xmlUrl, $http, $log)
		.success(function(data, status) {
			//$log.info('Success');
			$scope.jsonEntries = data;
		}).error(function(data, status) {
			//$log.info('Error ' + data);
			$scope.jsonEntries = data || "Request failed";
		});
	};

	$scope.renderEntries();
});

6. Definiendo nuestra vista parcial.

Nuestra vista faq.html mostrará la lista de preguntas y respuestas. Esta vista es cargada dinámicamente por angularJs dentro de nuestra página de inicio. Esta vista estará usando un componente nuevo llamado <parse></parse>, el cuál será creado mas adelante mediante la implementación de una directiva de angularJs.

<div>Preguntas Frecuentes<div>
<ul class="lista">
	<li ng-repeat="pregunta in jsonEntries.faq.e">
	  <parse myclass="pregunta" texto="{{pregunta.pregunta}}"></parse>
	  <parse myclass="respuesta" texto="{{pregunta.respuesta}}"></parse>
	</li>
</ul>