Let's Code!

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(/</g, '<').replace(/>/g, '>');
					var htmlText = '<div class="'+ attrs.myclass +'">' + str +'</div>';
					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!

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>

3. Modificando el enrutador en mi módulo.

El Archivo app.js, crea nuestro módulo en angularJs, importa los módulos del servicio y directiva que usaremos, además indica el controlador para nuestra página de preguntas frecuentes.

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

4. Modificando mi página de inicio.

El Archivo index.html, es la página de inicio en donde incluiremos todos los archivos javascript, asi como las hojas de estilos. Además es la encargada de contener la vista parcial.

<html ng-app="miModulo">
<head>
<meta charset="utf-8">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js"></script>

<script src="resources/javascript/app.js"></script>
<script src="resources/javascript/controllers.js"></script>
<script src="resources/javascript/services.js"></script>
<script src="resources/javascript/directives.js"></script>
<link href="resources/css/main.css" rel="stylesheet" type="text/css">
<script src="resources/javascript/xml2json.js"></script>

</head>
<body>
<div id="wrapper">
	<div class="menu">
		<a href="#/">Home</a>|
		<a href="#/auto">Auto</a>|
		<a href="#/faq">FAQ</a>
	</div>
	<hr/>
	<div ng-view></div>
</div>
</body>
</html>

0. Estructura de la solución.

Estructura de Archivos de la Solución.

1. El archivo de datos XML.

Antes de empezar a implementar, necesitamos definir la estructura de nuestro archivo XML. Este contendrá una lista de entradas, cada entrada esta conformada por una pregunta y una respuesta.

El archivo tendrá por nombre data.xml y lo ubicaremos dentro del sub-folder data en el directorio raíz. Entonces definimos nuestro archivo XML de la siguiente manera:

<faq>
<e>
	<pregunta>Qué es AngularJs?</pregunta>
	<respuesta>Un framework javascript MVW.</respuesta>
</e>
<e>
	<pregunta>Qué es MVW?</pregunta>
	<respuesta>Model View Whatever.</respuesta>
</e>
<e>
	<pregunta>Qué quiere decir Whatever?</pregunta>
	<respuesta>Que puede comportarse como MVC o como MVVM. Whatever works for you!</respuesta>
</e>
<e>
	<pregunta>Dónde puedo encontrar mas documentación?</pregunta>
	<respuesta>visita &lt;a href="http://angularjs.org"&gt;angularjs.org&lt;/a&gt;</respuesta>
</e>
</faq>

2. Cómo obtengo la informacion desde el archivo XML?

Crearemos un servicio con angular que se encargue de realizar un GET asincrono al archivo de datos, lo que obtendremos sera un string. Ahora cómo podemos convertir ese objeto string en un array de objetos, esto es un objeto JSON?

Indigando un poco, encontré la respuesta [aquí], es una librería javascript llamada xml2json, que se encarga de convertir objetos XML o String XML a objetos JSON que pueden ser manejados rápidamente por nuestra aplicación.

Entonces para crear nuestro servicio en angularJS, editamos nuestro archivo services.js. Este archivo javascript contiene todos nuestros servicios que usaremos en nuestra aplicación. El código fuente es el siguiente:

'use strict';
/* jFaq Service */

var jFaqServices = angular.module('jFaq.services', []);

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

jFaqServices.service('jFaqService', function() {

	this.getJsonEntries = function(xmlFileUrl, http, log) {
		return http({
			method: 'GET',
			url: xmlFileUrl,
			headers: {
				'Accept': 'application/xml'
			},
			transformResponse: function(data) {
				//log.info('DATA = ' + data);
				var json = xml2json.parser( data , 'a');
				return json;
			},
			cache: false,
		});
	};
});

De dónde nace la idea..

En cada sitio web, siempre nos vemos en la necesidad de contar con una página de preguntas frecuentes, también conocida como FAQ page, que sirva como ayuda a los visitantes de nuestro sitio web.

La implementación de estas va desde los más complejos casos, en donde el usuario final puede formular preguntas, encuestas y compartirlas dentro del sitio, las cuales son revisadas por un administrador, quien se encarga de darles respuesta; hasta las simples paginas estáticas, que muestran una lista de preguntas pre-definidas antes de publicar el sitio, si bien es cierto que el usuario final no puede crear preguntas nuevas pero que sin duda alguna le sirven de ayuda.

Desde el punto de vista del programador, los casos complejos brindan una solución muy flexible al usuario final, pero como todo lo bueno, cuesta más el desarrollarlos. El caso simple, estático, no brinda una buena solución al usuario, puesto que para agregar nuevas preguntas, necesitaremos de alguien que edite el markup de la página y agregue nuevos elementos para que la nueva pregunta se visible por el usuario final.

Que solución debo implementar?

Pensando en ello, imagine poder crear una FAQ page, que sea simple sencilla como las estáticas, pero que a la vez se puedan agregar más preguntas sin editar o modificar el markup elaborado por un diseñador o programador. Aquí es donde me imagine usar un componente poderoso llamado angularJs directivas.

AngularJs es un framework javascript MVW, entre sus principales características, nos permite extender nuestro lenguaje de markup, dentro de nuestra aplicación web. Estas extensiones se hacen usando directivas.

La solución que se me vino a la cabeza, fue la de crear un componente con angularJs que tenga como atributo el URL de un archivo XML, el cual contendrá las preguntas y respuestas. Mi FAQ page contendrá código HTML en el cual colocare el componente quien se encargara de obtener la información del archivo XML y presentarlas en forma de lista en la página, si se necesitan agregar más preguntas y repuestas bastara con agregarlas al archivo XML y no habrá necesidad de cambiar el markup de mi página.

Bien, manos a la obra!

Probando el editor de codigo fuente .

if(a == "hola") {
  a++;
}

Hello world!

Welcome to WordPress.com. This is your first post. Edit or delete it and start blogging!