Multiples estados
Actualmente contamos con una sola pantalla que muestra todas las noticias actuales y un pequeño formulario para poder agregar una nueva noticia. Deseamos que cuando el usuario haga click en alguna noticia la aplicación pase a un nuevo estado en dónde se muestre esa sola noticia en pantalla junto a la lista de sus comentarios.
Vamos a crear un nuevo componente para este nuevo "estado". Lo llamaremos PostDetailComponent
src/frontend/app/components/postDetail.component.js
Observamos dos cosas:
- Reusa al componente
PostComponent
que ya habíamos definido con anterioridad. Gol. - Hace referencia a un componente
<comment>
que es cotrolado porCommentComponent
. El mismo luce algo así:
src/frontend/app/components/comment.component.js
Estados de nuestra aplicación
Entonces desde ahora podemos decir que nuestra app tiene dos estados posibles:
- Uno representado por
PostDetailComponent
que renderiza una noticia con sus comentarios - Otro que renderice a todas las noticias y al form para crear una nueva. Actualmente se encuentra dentro de
AppComponent
pero es una buena idea introducir un refactor y llamar a todo esoPostListComponent
.
src/frontend/app/components/postList.component.js
Conservaremos AppComponent
como el punto de entrada a nuestra aplicación que delegará (de momento) solo en el estado PostListComponent
src/frontend/app/components/app.component.js
Importante. No olivdemos que debemos registrar todos estos estados nuevos en nuestro @NgModule
src/frontend/bootstrap.js
Angular router
Introduciremos entonces al modulo de angular llamado router. El mismo es justamente una máquina de estados que decide que componente renderizar en función de la url del browser.
Primero nos instalaremos el módulo @angular/router
por medio de npm
$ npm install @angular/router --save
En donde configuramos nuestro NgModule (bootstrap.js
) importaremos y configuraremos el router de la siguiente forma:
src/frontend/bootstrap.js
Aquí definimos dos urls (o rutas) posibles. La primera /noticias
que rederizará el componente PostComponent
y la segunda /noticia/:id
que renderizará el componente PostDetailComponent
. Adicionalmente definimos que cualquier pedido a /
sea redirigido a /noticias/
Para completar la configuración del router deberemos cambiar dos cosas:
Debemos registrar
router
como dependencia de nuestro modulo. Simplemente lo agregaremos a la lista deimports
en el decorator@NgModule
:imports: [ router, BrowserModule, FormsModule, HttpModule ]
Debemos cambiar nuestro componente
AppComponent
una vez para no tener harcodeada una referencia a<postList>
sino que delegue en el router para representar cualquiera de los estados que se encuentra actualmente activo. Para hacer eso necesitamos cambiar su template por el siguiente:
<h1>Bienvenidos a {{name}}</h1>
<router-outlet></router-outlet>
<router-outlet>
es justamente un componente provisto por el RouterModule
que se encargará de dinamicamente renderizar uno u otro estado.
Links entre estados
Necesitamos definir links para navegar entre estados. Para usaremos la directiva routerLink
. Agregaremos dos links, uno en la lista de noticias para ir al detalle y otro en el detalle para volver a la lista de noticias:
src/frontend/components/postList.component.js
y
src/frontend/components/postDetail.component.js
La directiva routerLink recibe un array de n posiciones representando segmentos de la ruta a la que apunta (un segmento es cada pedacito de la ruta entre /
). Por ejemplo, [routerLink]=['/blah','bleh,'blih']
apuntará a la ruta /blah/bleh/blih
.
La razón por la que especificamos el nombre de la directiva entre []
es porque deseamos que bindee (o que reaccione ante cualquier cambio) de la expresión ['/noticia', item._id]
.
Probamos y casí casí anda! Al hacer click sobre una noticia navegamos al detalle... aunque el detalle se rompe
Pasando parametros entre rutas
El detalle se rompe porque justamente nos falta asignar un valor a this.post
. La url con la que llegamos a dicho estado contiene el id de la noticia /noticia/:id
, deberíamos poder extraer el valor de dicho id y recuperar la noticia en base a eso.
Para eso necesitaremos que se nos inyecten dos objetos en nuestro componente:
ActivatedRoute
- la misma contendrá información (y lo que mas nos interesa, los parametros) de la ruta que se encuentra actualmente activa en el router.PostService
- para poder recuperar una noticia en base a su id.
Modificaremos PostDetailComponent
para recibir esos dos objetos
src/frontend/components/postDetail.component.js
Luego utilizamos dichos objetos para recuperar el valor de this.post
src/frontend/components/postDetail.component.js
Varias cosas:
ngOnInit
es una función la cuál, si existe, es llamada por angular durante la inicialización de nuestro componente. Sería analoga al constructor pero, por razones de convención, angular aconseja colocar toda inicialización en dicho punto.this.route.params
no es un objeto con todos los parametros como uno intuíría sino un objeto de tipoObservable
. Los observables entienden el mensajesubscribe
con un callback el cual será invocado cada vez que alguno de esos parametros cambie.this.postService.getPost
es un nuevo método que agregamos a post service el cuál retorna una promise que se resuelve a una noticia y está implementado de la siguiente forma:
src/frontend/services/post.service.js
GitHub
Como referencia dejamos el estado del proyecto en GitHub