AngularJS. Framework JavaScript para Webapps

elad . lunes 4 de marzo de 2013. a las 11:06

AngularJS framework javascript para webapps

En nitsnets | studios vamos a desarrollar un nuevo gran proyecto para una importante multinacional. Un B2B (business to business) de la que pronto podremos contar más. El reto: desarrollar toda la intranet sin lenguaje servidor ya que la capa de lógica de negocios está totalmente implementada por webservices y por tanto la creación de una Webapp o Web Application con tecnología estándar HTML/CSS3/Javascript para la correcta visualización en multiplataforma y multidispositivo.

Después de tiempo investigando y planteando incluso una solución realizada a medida con nuestro jefe de proyectos Alex Such dimos con la solución: AngularJS un framework javascript MVC que se adapta a la perfección y encaja a todo lo que habíamos ideado. Para los más flasheros un sustituto ideal con tecnología estándar web de las RIAs (Rich Internet Application) creadas con Flex.

Durante este artículo os mostraremos un ejemplo de cómo empezar y una buena forma de organizarnos con AngularJS

¿Qué es AngularJS?

AngularJS es un impresionante framework javascript opensource desarrollado por Google. Un framework para crear Webapps en lenguaje cliente con Javascript ejecutándose con el conocido single-page applications (aplicación de una sóla página) que extiende el tradicional HTML con etiquetas propias (directivas) como pueden ser ng-app, ng-controller, ng-model, ng-view…

Un framework basado en MVC (Modelo-Vista-Controlador) increíblemente flexible, de muy fácil lectura y desarrollo rápido (puedes empezar en minutos).

Permite extender HTML con tags personalizados, definir y vincular (data-binding) variables vista/controllador, consultas ajax con peticiones HTTP, sistema óptimo de templating, manipulación de datos en JSON, inyección de dependencias, deep linking, formularios de validación, desacoplamiento del DOM de Javascript, internacionalización i18n y l10n, filtros, unit testing

AngularJS es compatible con los navegadores de última generación (Chrome, Firefox, Safari, Opera, Webkits, IE9+) y se puede hacer compatible para Internet Explorer 8 o anterior mediante varios hacks

Proyecto: listado de libros y acceso a su ficha


http://lostiemposcambian.com/blog/posts/angular-js/

ver demo

La aplicación final es muy sencilla y similar al tutorial oficial de AngularJS de Google, vamos a intentar hacer un paso a paso en español y explicando algunos detalles más no exclusivamente a nivel de código como la organización de los ficheros y clases del framework. La aplicación consta de un listado de libros obtenido de una petición ajax a unos datos JSON desde el servidor, además de un filtrado vía javascript y cambio de página a la ficha de cada libro.

Estructura de ficheros y organización

El framework AngularJS se carga con la inclusión de un único fichero http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.min.js. Realmente AngularJS no indica (como en otros frameworks) cuál seria la estructura de carpetas a seguir. Nosotros hemos planteado la siguiente organización por similitud y experiencia en otros frameworks:

estructura y organización proyecto framework AngularJS

Las carpetas del raíz son:

  • css/ estilos CSS de la interfaz
  • data/ ficheros JSON de datos. No sería necesario si invocáramos a servicios web.
  • img/ imágenes de los libros
  • lib/ podría haber librerías de javascript comunes a todos los proyectos. No está en este ejemplo.
  • src/ todo el código javascript de nuestra aplicación
  • index.html HTML principal que carga toda la aplicación

Realmente la estructura importante es donde se encuentra nuestra aplicación en src/:

  • config/ constantes de configuración como rutas, urls de conexión a WS, etc… No utilizado en este ejemplo
  • controllers/ controladores de la app.
  • directives/ componentes o etiquetas extendidas de HTML. No utilizado en este ejemplo
  • filters/ filtros para búsquedas de objetos. No utilizado en este ejemplo
  • lib/ librerías javascript.
  • models/ modelos. No utilizado en este ejemplo, directamente el modelo en el ejemplo es el propio JSON pero se podría encapsular en la carpeta models
  • services/ servicios de la app. Llamadas a los webservices. No utilizado en este ejemplo, las llamadas simples las haremos desde el controlador
  • views/ vistas de la app. Vistas y parciales de vista
  • app.js inicialización de la aplicación. Donde se encuentra el routing

Inicialización de la APP. ng-app

index.html


<!doctype html>
<html lang="es" ng-app="app">
<head>
	<meta charset="utf-8"> 
    <link href="css/estilos.css" rel="stylesheet" media="screen">
    
	<title>Libros APP . AngularJS</title>
	<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.min.js"></script>
    
    <script src="src/app.js"></script>
    <script src="src/controllers/LibrosListController.js"></script>
    <script src="src/controllers/LibroDetailController.js"></script>
   
</head>

<body>

	<div ng-view></div>
    
</body>
</html>

Toda la aplicación pasará siempre por index.html donde cargaremos AngularJS y todas las clases javascripts necesarias. Para que AngularJS haga efecto tenemos que poner la directiva ng-app y para poder referenciarla dar un nombre a nuestra aplicación, en este caso app: <html lang=»es» ng-app=»app»>.

Cargamos los javascript de inicialización de la aplicación app.js y los controladores de la aplicación LibroDetailController.js y LibrosListController.js.

Por último definimos el cajón donde los controladores irán cambiando las vistas mediante la directiva de AngularJS ng-view: <div ng-view></div>

Routing

En la inicialización de la aplicación definimos las rutas con los pares Controlador-Vista. De esta manera podremos definir la ruta que muestra la aplicación mediante slash #

src/app.js

angular.module('app', []).

  //definimos las rutas de la 'app'
  config(['$routeProvider', function($routes) {
  
  $routes.
      when('/libros', {
		  templateUrl: 'src/views/libros-list.html',
		  controller: LibrosListController
		  }).
	  
	  //mediante dos puntos (:) definimos un parámetro
      when('/libro/:libroId', {
		  templateUrl: 'src/views/libro.html',
		  controller: LibroDetailController
		  }).
	 
	  //cualquier ruta no definida  
      otherwise({
		  redirectTo: '/libros'});

}]);

En este ejemplo tendremos dos rutas http://www.midominio.com/#/libros para el listado de libros y http://www.midominio.com/#/libro/1 para la ficha de un libro.

Mediante la llamada $routes.when definimos la url y el par controlador-vista a ejecutar. Por ejemplo, en la ruta #/libros ejecutará el controlador LibrosListController.js y cargará la vista src/views/libros-list.html en el div de index.html que tiene la directiva ng-view.

Como se puede apreciar mediante dos puntos : podemos también pasarle parámetros. En este caso a la ficha del libro le pasaremos como parámetro el identificador del mismo :libroId

Con otherwise podemos definir una ruta por defecto haciendo redirect en cualquier ruta que no corresponda a las ya definidas. En el ejemplo si la ruta no la encuentra irá a la home que es lo mismo que ir a #/libros

Vista

El listado de libros será la home de nuestra aplicación. Se llamará al controlador LibrosListController.js y se pintará la vista libros-list.html en ng-view de index.html.

src/views/libros-list.html

<h2>Libros</h2>
<span class="mini">{{var1}}</span>
 
<ul>
    <li ng-repeat="obj in libros">
    	<a href="#/libro/{{obj.id}}"><img ng-src="{{obj.img}}" width="95" height="150"></a>

         <p><a href="#/libro/{{obj.id}}">{{obj.titulo}}</a><br /><br />
               <strong>{{obj.editorial}}</strong><br />
               {{obj.descripcion}}</p>
    </li>
</ul>

Mediante las dobles llaves {{ var1 }} podremos pintar el valor de una variable definida en un controlador o en un modelo en la vista mediante ng-model. También entre llaves se pueden hacer operaciones javascript, por ejemplo {{ 2+1 }} sacaría en la vista 3.

Con la directiva ng-repeat repetimos la etiqueta donde fue definida tantas veces como objetos hayan. Lo cual lo hace muy cómodo, ya que permite foreach en la propia vista sin manchar el código: <li ng-repeat=»obj in libros»> pinta tantas etiquetas <li> con los datos como objetos libros se reciban.
La vista estará esperando recibir objetos libros en la variable libros con unos atributos id, titulo, img, editorial, descripcion tal y como han sido definidos por el modelo.

Estos objetos libros podrían ser definidos como variable en el controlador así:

...
$scope.libros = [
    {"id": "1",
     "titulo": "El Juego de Ender"
    },
    {"id": "2",
     "titulo": "Juego de tronos"
    },
   {"id": "3",
     "titulo": "I robot"
    },
  ];

o ser cargados desde un JSON como en el ejemplo data/libros.json

[
   {
	 "id": "1",
	 "titulo": "El Juego de Ender",
	 "autor": "Orson Scott Card",
	 "editorial": "Ediciones B / Zeta",
	 "descripcion": "La Tierra está amenazada por una especie extraterrestre de insectos que pretende destruir la humanidad. Para vencerlos se precisa la intervención de un genio militar, por lo cual se permite el nacimiento de Ender, tercer hijo de una pareja en un mundo que limita a dos el número de descendientes. Ender se entrenará en una estación espacial, superará a sus rivales y se convertirá en la persona capaz de dirigir las flotas terrestres contra los insectos de otros mundos.",
	 "img": "img/img1.jpg"
	},
	{
	 "id": "2",
	 "titulo": "Juego de tronos",
	 "autor": "George R. R. Martin",
	 "editorial": "Gigamesh",
	 "descripcion": "Tras el largo verano, el invierno se acerca a los Siete Reinos. Lord Eddard Stark, señor de Invernalia, deja sus dominios para unirse a la corte de su amigo el rey Robert Baratheon, llamado el Usurpador, hombre díscolo y otrora guerrero audaz cuyas mayores aficiones son comer, beber y engendrar bastardos. Eddard Stark ocupará el cargo de Mano del Rey e intentará desentrañar una maraña de intrigas que pondrá en peligro su vida y la de todos los suyos. En un mundo cuyas estaciones pueden durar decenios y en el que retazos de una magia inmemorial y olvidada surgen en los rincones más sombríos y maravillosos, la traición y la lealtad, la compasión y la sed de venganza, el amor y el poder hacen del juego de tronos una poderosa trampa que atrapará en sus fauces a los personajes... y al lector.",
	 "img": "img/img2.jpg"
	},
	{
	 "id": "3",
	 "titulo": "I robot",
	 "autor": "Isaac Asimov",
	 "editorial": "Edhasa",
	 "descripcion": "Los robots de Isaac Asimov son máquinas capaces de llevar a cabo muy diversas tareas, y que a menudo se plantean a sí mismos problemas de 'conducta humana'. Pero estas cuestiones se resuelven en Yo, robot en el ámbito de las tres leyes fundamentales de la robótica, concebidas por Asimov, y que no dejan de proponer extraordinarias paradojas que a veces se explican por errores de funcionamiento y otras por la creciente complejidad de los 'programas'. Las paradojas que se plantean en estos relatos futuristas no son sólo ingeniosos ejercicios intelectuales sino sobre todo una indagación sobre la situación del hombre actual en relación con los avances tecnológicos y con la experiencia del tiempo.",
	 "img": "img/img3.jpg"
	}
]

El buscador no lo explicaremos en este post por abreviar un poco, pero en el código es muy fácil de entender (se encuentra en el ejemplo) así como el ng-model permitiendo una limpieza de código increíble.

Vista parcial

Pero también podríamos cargar mini vistas parciales para hacer más leíble el código. Podríamos encapsular la fichita del libro en una vista parcial transformando:

...
<ul>
    <li ng-repeat="obj in libros">
    	<a href="#/libro/{{obj.id}}"><img ng-src="{{obj.img}}" width="95" height="150"></a>

         <p><a href="#/libro/{{obj.id}}">{{obj.titulo}}</a><br /><br />
               <strong>{{obj.editorial}}</strong><br />
               {{obj.descripcion}}</p>
    </li>
</ul>
...

en

...
<ul>
    <li ng-repeat="obj in libros">
    	<div ng-include src=" 'src/views/_libro-detail.html' "></div>
    </li>
</ul>
...

Donde src/views/_libro-detail.html (por best-practice los nombramos con barra baja delante _) seria el trozo de código de la fichita esperando igual la variable obj (que es un libro)

<a href="#/libro/{{obj.id}}"><img ng-src="{{obj.img}}" width="95" height="150"></a>

         <p><a href="#/libro/{{obj.id}}">{{obj.titulo}}</a><br /><br />
               <strong>{{obj.editorial}}</strong><br />
               {{obj.descripcion}}</p>

Esto se realiza mediante la directiva de AngularJS ng-include. Hay que tener en cuenta que se utilizan las comillas simples ‘ ‘ para definir el path src=» ‘src/views/_libro-detail.html’ « y que dicho path tiene que ser desde la ruta principal (index.html) y no desde el parcial cargado. De esta manera nos queda el código limpísimo.

Es interesante ver en esta parte de la vista como mediante una llamada a un enlace simple <a href=»#/libro/{{obj.id}}»> {{obj.titulo}}</a> se evaluaría el routing y en este caso cargaría el controlador LibroDetailController.js cargando la vista libro.html con el id correspondiente a cada registro.

Controlador

Mediante el controlador podemos utilizar variables definidas en la vista o crear nuevas variables que serán utilizadas en la vista.

src/controllers/LibrosListController.js

function LibrosListController($scope, $http) {
  $http.get('data/libros.json').success(function(data) {
	$scope.libros = data;
  });
 
  //defines una variable
  $scope.var1 = "variable definida desde el controlador";
  
  //selecciona el desplegable y ordena automaticamente, variable definida en la vista con ng-model
  $scope.orderField = "titulo";
  $scope.orderReverse = "true";
}

Mediante $scope tienes el ámbito de la vista. Podemos definir variables para que las utilice la vista con $scope.var1 = «mi variable» (y en la vista visualizarla con {{var1}} ) o al revés, utilizar variables definidas en la vista como es el caso de $scope.orderField = «titulo»;.

Mediante $http puedes hacer peticiones ajax y recoger sus datos. En el ejemplo solicitamos una petición a un fichero estático data/libros.json y se crea una variable llamada libros en la vista con un array de objetos libros: $scope.libros = data; para poder mostrar los libros en la vista como vimos anteriormente.

Si nos fijamos en el otro controlador: src/controllers/LibroDetailController.js

function LibroDetailController($scope, $http, $routeParams) {
  $scope.id = $routeParams.libroId;

  $http.get('data/libro'+$scope.id+'.json').success(function(data) {
	  $scope.libro = data[0];
  });
 
}

Podemos ver como mediante $routeParams podemos recuperar los parámetros dinámicos de la ruta definidos como vimos mediante dos puntos :libroId.

Seguir aprendiendo AngularJS…

Esperamos que en apenas unos minutos te hayas podido hacer con el espectacular framework de Google AngularJS. Si quieres seguir profundizando con AngularJS te recomendamos:

Conclusión: Webapps en cliente

AngularJS marca la transición entre páginas webs y aplicaciones web sin recarga de página, extendiendo las limitaciones de HTML. Una nueva tecnología que será muy utilizada en nitsnets | studios en este 2013.

Por supuesto, existen otros frameworks basados en JavaScript como podrían ser Backbone.js y el mas reciente Ember.js que comparten la misma filosofía que AngularJS, aunque personalmente nos hemos decantado por la tecnología de Google por mayor flexibilidad en conexiones REST, su potente sistema de templating y creador de tags e incluso menos código en data-binding.

Etiquetas: , , , ,

57 Comentarios
» Feed RSS de los Comentarios

  1. Toni dice:

    Muchas gracias por el artículo! me viene que ni pintado jeje
    Sin duda lo que más me gusta de Angular es el data binding, nostalgia de Flex 🙂
    Un saludo!

  2. Iván dice:

    Que buena pinta tiene, me lo voy a tener que mirar… 😉

  3. Joan dice:

    Genial el tutorial, pero deja con ganas de más 😉

    A ver si nos amplias con la parte de las ditectives, filters o servies.

    Pero lo dicho, genial y gracias

  4. elad dice:

    Muchas gracias por los comentarios!!!!
    Nos motivan mucho a seguir escribiendo!!!

    Joan, estamos preparando uno justamente sobre directives avanzadillo; a ver si pronto lo podemos publicar!

  5. Manu dice:

    Un artículo muy completo, muestra que el presente y el futuro sin duda está en javascript

    Un saludo, de un nuevo seguidor en twitter

  6. Jose Carlos dice:

    Exelente!!!!
    Gracias por este gran aporte. Sigue así compartiendo.
    Muchas gracias.
    Un brazo.

  7. Lorenzo Jiménez (@lorenzosjb) dice:

    Bajé el ejemplo y desde Chrome 27, Opera 12 y Explorer 10 sale una pantalla en blanco. En Firefox 21 sale descuadrado pero funciona y Safari 5.1.7 funcionó y se visualizó bien.

  8. elad dice:

    Buenas Lorenzo, desde http://lostiemposcambian.com/blog/posts/angular-js/ no te funciona bien?

    Teóricamente utiliza Angularjs solamente y no ha dado ningún problema 🙂

  9. danii dice:

    Buenas Lorenzo! Abre la consola de JavaScript (en Chrome Dev Tools) y comprueba si tienes el siguiente error:

    XMLHttpRequest cannot load file://path/to/folder/angularjs/src/views/libros-list.html. Origin null is not allowed by Access-Control-Allow-Origin.

    Puesto que Angular carga los templates utilizando AJAX es posible que algunos navegadores por seguridad impidan carga de archivos via file://. Diferentes navegadores modernos siguen diferentes políticas de SOP (Same Origin Policy) en lo que respecta a archivos locales. Creo que Chrome y Opera siempre han sido de los más estrictos al respecto, el caso de Explorer 10 me ha sorprendido la verdad.

    Solución para no tener estos problemas: debes instalar un web server local, meter la carpeta con el proyecto en la carpeta pública de http documents y probar esta demo via URLs http, por ejemplo desde http://localhost/

    Esperamos que esto te ayude!

  10. Lorenzo Jiménez (@lorenzosjb) dice:

    Muchas gracias. Efectivamente es un asunto del navegador.

  11. Sergio Flores dice:

    Mi consulta es si alguien lo ha probado con BoilerPlate ?

  12. Percy dice:

    Interesante este framework pero para un desarrollo profesional que aplicaciones o recursos debemos tener para complementar como por ejemplo que base de datos,servidor web par poder integrarlos a nuestra aplicación web.

  13. Percy dice:

    tengo un json de esta forma y no puedo obtener la data:
    $http.get(‘http://190.216.168.107/api/v1/item/?format=json’).success(function(data) {
    $scope.libros = data;
    //console.log(data);
    }).error(function(data) {
    console.log(‘Error 111: ‘ + data);
    });

    {
    meta: {
    limit: 20,
    next: null,
    offset: 0,
    previous: null,
    total_count: 2
    },
    objects: [
    {
    item_codcomer: «8BM000000015»,
    item_codi: «8BM000000015»,
    item_nomb: «ARROZ CON LECHE «,
    resource_uri: «/api/v1/item/8BM000000015/»,
    tunid: «09»,
    unid_codi: «/api/v1/unid_codi/9/»
    },
    {
    item_codcomer: «8BM000000016»,
    item_codi: «8BM000000016»,
    item_nomb: «ARROZ CON LECHE VIP «,
    resource_uri: «/api/v1/item/8BM000000016/»,
    tunid: «09»,
    unid_codi: «/api/v1/unid_codi/9/»
    }
    ]
    }

  14. elad dice:

    Buenas Percy:
    Realmente el JSON esta bien formado y seguro que te llega el data correctamente!

    En el callback donde te llega data te llegará correctamente!

    Lo único que para entrar dentro de item_codcomer tienes antes que entrar en objects del tipo $scope.libros.objects[0].item_codcomer

    Espero que te sirva!

  15. Cristian dice:

    Hola, muy buen ejemplo y tutorial, es de los pocos que esta bien explicado, pero tengo una duda la versión con que se trabaja de angular es la 1.04, cuando le coloco la ultima versión la 1.2.11 no me funciona nada, me sale este error en consola: Uncaught Error: [$injector:modulerr] .. no se por que puede pasar esto?? soy un poco novato espero me puedan ayudar…

  16. elad dice:

    Hola Cristian

    Desde la versión 1.2 se introdujeron una serie de cambios que afectan a la preparación del entorno. Se sacaron muchas cosas del core a módulos externos, para hacer posible que una aplicación AngularJS fuera lo más ligera posible y que cada desarrollo incluyera sólo los elementos necesarios. Uno de los módulos afectados es el de rutas, que ahora hay que incluirlo explícitamente:

    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular-route.min.js"></script>

    Y, como se trata de un módulo, habría que incluirlo en nuestra aplicación (app.js)

    angular.module(‘app’, [‘ngRoute’])

    Con esto, nuestras rutas volverían a funcionar de igual manera que en una versión pre-1.2. Dejamos un fichero con una variación de la aplicación que presentamos en el artículo, y funciona en la v1.2.12:
    http://www.lostiemposcambian.com/blog/posts/angular-js/angular-js-1.2.12.zip

    Puedes encontrar más información del módulo de rutas en http://docs.angularjs.org/api/ngRoute.

    Espero que te sirva!!! Suerte con tus aplicaciones!

  17. santos dice:

    hola que bien está el framework emprezaré a probarlo

  18. dlupah dice:

    Gracias por el post, pero me gustaría tener más información sobre cómo se gestiona la seguridad (autenticación, autorización, roles, sesión de usuario…) en angular, ya que en la mayoría de aplicaciones productivas, esto es un punto muy importante y que normalmente se suele gestionar desde la parte servidora.
    ¿cómo se resolvería el caso en el que el ejemplo de los libros, tuviera usuarios con distintos perfiles, en el que algunos no tuvieran acceso al listado y los que si lo tuvieran, algunos pudieran acceder al detalle y otros no?

  19. elad dice:

    Buenas dlupah!
    Gracias por los comentarios! Esperamos en un futuro escribir más sobre Angularjs

    Sobre que tuvieras usuarios con distintos perfiles tendrías que hacer un sistema de loguin y almacenar el id del usuario en una session (por ejemplo) o pasar dicho id en la petición de los libros en el controlador donde haces la solicitud. En este caso en:

    function LibrosListController($scope, $http) {
    $http.get(‘data/libros.php?id_user=2’).success(function(data) {
    $scope.libros = data;
    });
    }

    En el acceso al detalle también podrías detectar al usuario y expulsarlo o mostrar sólo la info si es autorizado haciendo lo mismo en la petición 🙂
    espero que te sirva!

  20. Fabián dice:

    Excelente tutorial, muchas gracias x la dedicación… Saludos!

  21. Tadeo dice:

    Que milagro que no optaron por EXTJS 4 , ahora 5, veo que Extjs para proyectos grandes es muy poderoso.

  22. Lorenzo dice:

    Tadeo, extjs es cobrado por Sencha mientras que Angular es gratis.

  23. Muchas gracias por el tutorial y el ejemplo para descargar. Es como mejor se aprende.

    Un saludo!

  24. Jose dice:

    Hola, intente probar el ejemplo pero me da el siguiente error «El uso del atributo especificado en atributos está desaprobado. Siempre devuelve verdadero. @ http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.min.js:38» el problema es que no reconoce el atributo ng-repeat. No se si esto pueda ser culpa del navegador pero lo intente con firefox v24.0.0 y internet explorer v11

  25. Jose dice:

    Xd.. la aplicacion la tengo montada en IIS 7

  26. elad dice:

    Buenas Jose,
    desde la versión 1.2 se introdujeron cambios de core y cambiamos el ejemplo. Parece que tienes uno antiguo pq ahora el ejemplo esta con la versión 1.2.12.

    Prueba de descargarte este y a ver si te funciona:
    http://www.lostiemposcambian.com/blog/posts/angular-js/angular-js-1.2.12.zip

    Recuerda que tienes que abrirlo desde un servidor web no desde local, en principio si el que tienes es IIS debería funcionar sin problemas!!

    Espero que te sirva de ayuda!

  27. Jose dice:

    Hola elad, gracias por responder. Probe e; ejemplo que me distes y me da el mismo problema. Luego descubri que lo que pasa es que la funcion $http.get(url) dentro del controlador nunca se dispara por lo que data queda vacio. si en vez de eso simplemente pongo directamente:
    $scope.libros = [{«id»: «1»,
    «titulo»: «El Juego de Ender»,
    «autor»: «Orson Scott Card»,
    «editorial»: «Ediciones B / Zeta»,
    «descripcion»: «La Tierra …»}];
    si funciona.

  28. elad dice:

    Es muy extraño lo que comentas!
    Quizás tengas el server capado y no permites peticiones a formatos .JSON

    La llamada $http.get(url) es la petición AJAX al servidor aunque esta hecha con un fichero estático 🙂

  29. Jose dice:

    Si, tenias razon, el pto era que el servidor no armitia los formatos json.
    GRACIAS!!!

  30. Camilo Serna dice:

    Buen día, ¡muy bueno el tutorial!

    Tengo algunas cuestiones:

    – Si ejecuto el archivo index.html con doble click, funciona bien, pero usando wampserver voy a localhost y cuando entro a la carpeta dice: «Forbidden

    You don’t have permission to access /angularjs/index.html on this server.» ¿Ésto a qué se debe?.

    – Lo otro es que ando siguiendo el código para tratar de entenderlo bien, tengo algunas dudas por ejemplo en la línea «$scope.libros = data;» ¿es la misma que luego se usa como «obj.titulo» «obj.editorial» y «obj.descripcion»?, es decir, ¿no es necesario usar el mismo nombre del objeto?. Veo que otras variables si se usan con el mismo nombre como el caso de «$scope.var1» y luego se usa así {{var1}}.

    – Algo más, es que quiero saber cómo funciona lo de la búsqueda y el ordenamiento, en el tutorial dice que eso se ve en el código pero la verdad lo único que veo es: «ng-model=»query.titulo» y «ng-repeat=»obj in libros | filter:query | orderBy:orderField:orderReverse», ni idea de dónde estará el código para eso, ¿acaso es alguna cosa que angular.js tiene implimentado?, y que con sólo poner esas etiquetas ¿angular.js hace el trabajo?.

    Gracias!

  31. Camilo Serna dice:

    Hola de nuevo!
    Disculpen la primera de las cuestiones que cite anteriormente:

    /*»Si ejecuto el archivo index.html con doble click, funciona bien, pero usando wampserver voy a localhost y cuando entro a la carpeta dice: “Forbidden

    You don’t have permission to access /angularjs/index.html on this server.” ¿Ésto a qué se debe?.» */

    Ya sé por qué fue, porque saque los archivos del zip sin discomprimirlo algo hace eso y por eso no me daba acceso, la descomprimí, la abri y va bien.

    Las otras dudas si aún persisten 😀

  32. elad dice:

    Buenas Camilo:
    El primer punto tiene pinta de que tienes algo mal configurado con Wamp,
    quizás esto te ayude: http://stackoverflow.com/questions/8366976/wamp-error-forbidden-you-dont-have-permission-to-access-phpmyadmin-on-this-s

    El punto dos:
    $scope es el ámbito. Cuando en un controlador defines $scope.libros en la vista html ya tienes la variable libros para ser utilizada (como en el caso de $scope.var1).
    Después en la vista se accede a obj.description porque realizamos un foreach con la directiva de angularjs ng-repeat=»obj in libros»

    Sobre la búsqueda angularjs tiene implementada esa posibilidad que es muy cómoda sobre la directiva ng-repeat
    La variable bindeada query es la que se utiliza para la búsqueda siendo definida en el ng-model
    Puedes leer más en:
    https://docs.angularjs.org/api/ng/directive/ngRepeat
    https://docs.angularjs.org/api/ng/filter/filter
    https://docs.angularjs.org/api/ng/directive/ngModel

    Espero que te sea de ayuda!

  33. Camilo Serna dice:

    ¡Muchas gracias!, entiendo, respuesta muy oportuna, seguiré viendo muchos tutos aquí 😀

  34. Camilo Serna dice:

    Buen día Elad,

    Consultando varias cosas (que como le comentaba ando buscando las mejores opciones para desarrollar un proyecto que tengo en mente) me encontré con algo bien interesante.

    Viendo y viendo llegue a Synfony un MVC de PHP, realmente quería hacer el servidor en Node.js pero pues tampoco quiero complicarme mucho ya que PHP si lo he trabajado más.

    Lo que veo es que este framework Synfony usa un lenguaje al que le llaman Twig, viendo cosas al respecto de ese lenguaje descubro que es exactamente lo que se muestra aquí en el ejemplo de Angular.js en la parte de HTML. Y pues para usar ese Twig se deben instalar ciertas cosas, segun los tutos.

    Por el momento mi pregunta es:
    1. La libreria Angular.js ¿tiene todo para poder programar en Twig o este código es propio de Angular.js sólo que son iguales en sintaxis?, es decir, ¿{{var1}} es tanto Twig como Angular.js?.

    De acuerdo a su respuesta quiesiera hacerle otras preguntas, ¡gracias!

  35. elad dice:

    Buenas Camilo,
    Twig no tiene nada que ver con Angularjs, que algunas sintaxis se parezcan es lógico pero no tiene nada que ver.

    Twig es un motor de plantillas para vistas en el desarrollo web con PHP http://twig.sensiolabs.org/
    Es el motor de plantillas que utiliza como dices Symfony (de hecho ha sido creados por ellos). No obstante lo puedes utilizar en un proyecto PHP sin Symfony también.

    Algo hemos escrito sobre Twig: http://www.lostiemposcambian.com/blog/php/links-symfony2-plantillas-twig/

    Por tanto claro que puedes utilizar Angularjs con Twig pero es mezclar conceptos. Twig es para hacer una aplicación/web tradicional donde en cada petición pintas la vista (con Twig) en PHP. Cada petición tendrás recarga de página. Con Angularjs no tendrás esa recarga y es como que trabajas todo mediante AJAX. Espero que me entiendas. Mírate este primer video de Google: http://campus.codeschool.com/courses/shaping-up-with-angular-js/level/1/section/1/video/1
    Esta en inglés pero te dará luz para entender como funciona Angularjs con respecto al desarrollo web tradicional 🙂

    Por las cosas que preguntas te recomiendo no entrar con Symfony en PHP, tiene una curva de aprendizaje más grande y quizás te lleve mucho más esfuerzo. Nosotros estamos trabajando con Laravel (http://www.laravel.com) aunque lo más sencillo será meterte con Codeigniter (http://www.codeigniter.com), a pesar que han dejado de darle soporte los desarrolladores es el más sencillo de aprender de los frameworks MVC y que a nosotros nos ha dado grandes resultados: http://www.lostiemposcambian.com/blog/web-2-0/frameworks-php-symfony-vs-codeigniter-casos-de-exito/

    Espero que te sirva!

  36. Camilo Serna dice:

    Buen día Elad, ¡muchas gracias por su respuesta!

    No había dicho nada porque andaba viendo todos los videos del tutorial que me cito en ingles.

    La verdad lo entiendo pero ando como aburrido, porque a parte entender Angular.js quiero de una vez por todas saber el por qué usar este framework (o cualquier otro MVC). Al principio de los video-tutoriales bien, estaba concentrado y entendiendo pero luego llegue a un punto en el que pienso, usar Angular.js lo que hace es tener una gran cantidad de directivas en el HTML lo que no pasa con JQuery (queda limpio el HTML) y veo que tiene funciones de validación y otras herramientas (creo que también están en JQuery), sé que el framework sirve, pero no tanto por haberlo comprobado sino por lo que se dice en Internet, pero yo aún no veo cuál es la ventaja :/ no sé que mejora realmente a parte de los enrrutamientos (¿o es sólo eso?) y veo que haciendo tutoriales y cosas no voy a poder llegar a la conclusión.

    Me gustaría pedirle un favor más o menos grande, si puede sería grandioso, sino pues seguiré tratando de averiguarlo. Y es que porfa me muestre un pequeño ejemplo que tenga dos implementaciones, una sin Angular.js y otra con Angular.js, es decir, el mismo ejemplo con y sin Angular.js. Para ver si de una vez por todas le veo la magia a esto :/

  37. elad dice:

    Buenas Camilo,
    Creo que estas confundiendo conceptos: jquery es una librería… Angularjs es un framework.

    Con jquery trabajarás de forma más cómoda y ágil el javascript de una web. Angularjs te permitirá crear aplicaciones web escalables de forma eficiente y con código organizado.

    Por ejemplo Angulajs utiliza una versión modificada de jquery http://docs.angularjs.org/misc/faq.

    En muchos desarrollos de Angularjs también se utiliza jquery sobretodo por la gran cantidad de plugins y componentes que tiene jquery.

    Sobre el ejemplo es laborioso. Te animo si tienes conocimientos de jquery a que hagas el ejemplo de este artículo en jquery y luego compares tu código con el nuestro y verás la sencillez de angularjs y como lo organiza el framework de Google.

    De todas formas primero deberías entender el concepto de librería y framework para tener claro la diferencia.

    Espero que te sirva 🙂

  38. Carlos dice:

    Que tal Elad, soy nuevo en las aplicaciones web, y me topé con este framework que me parece bastante interesante y prometedor, he venido trabajando con una herramienta de automatización de proyectos «Gradle» y me gustaria utilizar o poder combinarla con AngularJS pero no se como tal como sería la estructura que debería llevar mi proyecto para que lo reconociera como una aplicaión web, no se si alguien me pudiese ayhudar con esto, o si alguien ya haya trabajado con esta herramienta utilizando AngularJS

  39. elad dice:

    Buenas Carlos:
    La verdad es que no conocíamos http://www.gradle.org/
    Tiene buena pinta!!

    Sobre la estructura del proyecto cada desarrollador acaba tomando sus decisiones pero es muy interesante leer sobre los best practice que el propio Google recomienda

    http://blog.angularjs.org/2014/02/an-angularjs-style-guide-and-best.html

    https://docs.google.com/document/d/1XXMvReO8-Awi1EZXAXS4PzDzdNvV6pGcuaF4Q9821Es/pub

    https://google-styleguide.googlecode.com/svn/trunk/angularjs-google-style.html

    Espero que te sirva de ayuda!

  40. Daymer dice:

    Muy bueno este post, me parece genial Angular y un poco facil ya que es MVC y en algunas cosas se parece a Twig

  41. Buen articulo elad, llevo hace un mes que estoy intentando aprender angular, lo estoy montando en un proyecto real: edelh.com el cual esta en zend fram 1.12 , pero tengo una duda que todavia no puedo decifrar:

    En la aplicacion zend tengo un controlador : miControlador y llamo a un archivo .js para dicho controlador, el tema es que tengo esto:

    $(document).ready(function(){
    $(«#nav-principal-top»).addClass(«linea-sombreada2»);

    })

    como cargar esto en angular js?
    no entiendo muy bien, investigando un poco, se puede hacer usando directivas; pero como vinculo esa directiva a dicho controlador?

    Espero poder recibir tu ayuda.

  42. elad dice:

    Pero hablas de poner jquery?
    Prueba en poner la inicialización con angular: ng-init=»nombreDeLaFunfion()» y esa función este en el scope.

    Una vez allí aplica el addClass de jquery
    espero que te sirva!!!

  43. Pero para ir aclarando el panorama, ya que tengo varias dudas de como implementar correctamente en un proyecto real y mediano,px los ejemplos que hay por la red son para cosas sencillas.

    Por ejemplo si tengo este menu de navegacion: quiero-contratar,quiero-trabajar-home que vendria a ser una vista + un controlador
    en angular en un archivo app.js tengo lo siguiente:

    ‘use strict’;

    var myModule = angular.module(«home», [
    ‘ngRoute’,

    ]);

    myModule.config([‘$routeProvider’, ‘$locationProvider’,
    function($routeProvider, $locationProvider) {
    $locationProvider.html5Mode(true);

    $routeProvider.when(«/», {
    templateUrl: ‘views/home.html’,
    controller: ‘homeCtrl’
    }).otherwise({
    redirectTo: ‘/’
    });

    $routeProvider.when(«/quiero-contratar», {
    templateUrl: ‘views/quiero-contratar.html’,
    controller: ‘quieroContratarCtrl’
    })

    }
    ]);

    cuando quiero aplicar esa clase jquery que te comentaba,este se mostraba en el home y solo era para la vista quiero-contratar, ademas de quiero que el codigo no se mezcle y que cada cosa funcione correctamente xque al final mediante gulp junto todo los archivos en uno solo.

    Ahora estaria bien tener un modulo para cada vista x decirlo asi:

    modulo quiero-contratar con su respectivo controlador y directivas
    ahi es lo quiero entrar en detalle.

  44. «AngularJS Paso a Paso”
    La primera guía completa en español para adentrarse paso a paso en el mundo de AngularJS
    En este libro podrás encontrar una forma fácil y entretenida de aprender AngularJS. Paso a paso te guiaré hacia las características que hacen único y espectacular este Framework de Javascript
    Adquiere tu copia en http://bit.ly/AngularJSPasoAPaso

  45. fatima dice:

    Buenos dias,
    Tengo un problema un codigo sencillo

    Cuaderno Alumnos

    {{alumno.nombre}} estudia {{alumno.telefono}}

    function alumnoController($scope){
    $scope.alumno = {
    nombre: «Juan Blanco»,
    telefono: «1234567890»
    }

    }

    y el resultado me sale asi
    {{alumno.nombre}} estudia {{alumno.telefono}}
    he buscado de todos las formas y maneras no veo donde tengo mal para que me sale los datos
    Alguien sabe el porque?
    Saludos

  46. elad dice:

    Buenas Fátima:
    Tiene pinta que no esta cargando bien el motor Angular o leyendo el controlador porque en principio tendría que estar mostrándote ya el contenido 🙂
    Envíanos si quieres el código (si no es muy complejo) quizás sobre el fichero podamos ayudarte!
    un saludo

  47. Libardo dice:

    Que mas, se me ha presentado una duda con respecto al ng-repeat y su interacción con las tablas, lo que quiero hacer es mostrar en una vista un documento Json, el cual contiene unos datos con nombre y id, con el ng-repeat creo 4 tablas que deben mostrar 4 datos por cada una de estas, lo cual lo hago con un filter, limitTo: 4,




    Nombre equipo

    {{ $index + 1 }}
    {{team.name}}

    pero cuando realizo la acción me muestra los mismos datos en todas las tablas y no he encontrado algo que me ayude con lo relacionado, que por cada tabla se muestren 4 {{team.name}} diferentes, no se si me he dado a entender, pero al igual quedo atento a cualquier comentario. Gracias

  48. elad dice:

    Buenas Libardo:
    Asi es complicado de ver que te esta sucediendo pq parece que todo esta bien armado.
    Envianos un email con el código de ejemplo (lo mas reducido posible al problema) y lo miramos 🙂

  49. pablo dice:

    Hola.

    Me ha gustado mucho tu post.
    Yo tengo creada una estructura de tres páginas no ngrouter.

    Una en la raiz «/» otra es «/otrapg» y una tercera «/otranuevapg».
    Me funciona perfectamente cuando pincho en link

    pero si quiero acceder directamente poniendo la ruta en el navegador de http://www.xxx.es/otrapg me da un error 404.

    Como puedo hacer que se pueda acceder directamente a estas páginas.
    Espero que me puedas ayudar ya que llevo varios días con este problema.

    Muchas gracias por atenderme.

Enviar comentario