Crea Tu Primera Aplicación Angular: Almacenando y Accediendo a Datos
Spanish (Español) translation by Rafael Chavarría (you can also view the original English article)
En el primer tutorial de la serie, aprendimos cómo comenzar para crear una aplicación Angular. Después de completar exitosamente ese tutorial, deberías tener ahora tu primera aplicación Angular funcionando con el encabezado "Datos Divertidos Sobre Países". Antes de crear cualquier componente que pueda ser generado en la pantalla, vamos a crear algunas clases y definir algunas funciones que hagan a ese componentes útiles.
En este tutorial, nuestro enfoque estará en crear una clase Country que contendrá diferentes propiedades cuyo valor queremos mostrar al usuario. Entonces crearemos otro archivo llamado country-data-ts. Este archivo contendrá información sobre todos los países en nuestra aplicación. Nuestro tercer archivo será nombrado country.service.ts. El nombre podría sonar rebuscado, pero el archivo solo contendrá una clase CountryService con toda la funcionalidad necesaria para recuperar y ordenar la información proporcionada por el archivo country-data.ts.
Creando una Clase País
Dentro de la carpeta src/app de tu aplicación Angular, crea un archivo llamado country.ts. Agrega el siguiente código dentro de este.
1 |
export class Country { |
2 |
name: string; |
3 |
capital: string; |
4 |
area: number; |
5 |
population: number; |
6 |
currency: string; |
7 |
gdp: number; |
8 |
}
|
El TypeScript de arriba define la clase Country con seis diferentes propiedades para almacenar información sobre diferentes países. El nombre del país, su capital, y su moneda son almacenados como una cadena. Sin embargo, su área, población, y PIB son almacenados como número. Estaremos importando la clase Country en muchos lugares, así que he agregado la palabra clave export antes de la definición de clase.
Creando un Arreglo de Países
El siguiente paso incluye crear un archivo country-data.ts para almacenar la información sobre todos los países como un arreglo de objetos Country. Estaremos importando la clase Country en este archivo y después exportando un const llamado COUNTRIES el cuál almacena un arreglo de objetos de país.
Aquí está el código para country-data.ts. Justo como country.ts, tienes que crear este archivo dentro de la carpeta src/app.
1 |
import { Country } from './country'; |
2 |
|
3 |
export const COUNTRIES: Country[] = [ |
4 |
{
|
5 |
name: 'Russia', |
6 |
capital: 'Moscow', |
7 |
area: 17098246, |
8 |
population: 144463451, |
9 |
currency: 'Russian Ruble', |
10 |
gdp: 1283162 |
11 |
},
|
12 |
{
|
13 |
name: 'Canada', |
14 |
capital: 'Ottawa', |
15 |
area: 9984670, |
16 |
population: 35151728, |
17 |
currency: 'Canadian Dollar', |
18 |
gdp: 159760 |
19 |
},
|
20 |
{
|
21 |
name: 'China', |
22 |
capital: 'Beijing', |
23 |
area: 9596961, |
24 |
population: 1403500365, |
25 |
currency: 'Renminbi (Yuan)', |
26 |
gdp: 11199145 |
27 |
},
|
28 |
{
|
29 |
name: 'United States', |
30 |
capital: 'Washington, D.C.', |
31 |
area: 9525067, |
32 |
population: 325365189, |
33 |
currency: 'United States Dollar', |
34 |
gdp: 18569100 |
35 |
},
|
36 |
{
|
37 |
name: 'Japan', |
38 |
capital: 'Tokyo', |
39 |
area: 377972, |
40 |
population: 12676200, |
41 |
currency: 'Yen', |
42 |
gdp: 4939384 |
43 |
}
|
44 |
];
|
La primera línea en este archivo importa la clase Country desde el archivo country.ts localizado en el mismo directorio. Si quitas esta línea desde el archivo, TypeScript te dará el siguiente error:
1 |
Cannot find name 'Country'. |
Sin la declaración de importanción, TypeScript no tendrá idea lo que significa un arreglo de tipo Country. Así que asegúrate de que has importado la clase adecuada y especificado la ubicación de country.ts correctamente.
Después de importar la clase Country, continuamos y creamos un arreglo de objetos Country. Estaremos importando este arreglo de países para usar dentro de otros archivos, así que agregamos una palabra clave export a este arreglo también. Actualmente, hay cinco diferentes objetos Country en el arreglo. Cada uno de estos cinco objetos proporciona pares llave-valor que listan el nombre de una propiedad y su valor para un objeto o país particular.
Si intentas agregar una propiedad adicional al arreglo el cuál no ha sido declarado dentro de la definición de clase Country, obtendrás el siguiente error:
1 |
Object literal may only specify known properties, and 'president' does not exist in type 'Country' |
En este caso, estaba tratando de almacenar el nombre del presidente como una string dentro de una propiedad llamada president. Ya que tal propiedad no fue declarada, obtuvimos un error. Algunas veces, podrías querer especificar una propiedad solo para objetos particulares y no para los otros. En tales casos, puedes marcar la propiedad opcional dentro de la definición de clase. He discutido esto a más detalle en un tutorial que cubre Interfaces TypeScript.
Por ahora, solo asegúrate de que los nombres de todas las propiedades coinciden los nombres dentro de la definición de clase. También asegúrate de que el valor de cada propiedad tiene el mismo tipo que se declaró en la definición de clase.
Creando una Clase CountryService
Después de crear nuestra clase Country y arreglo COUNTRIES, ahora podemos finalmente escribir funciones para procesar la información del país. Necesitaremos importar la clase Country y el arreglo COUNTRIES dentro de nuestro archivo de servicio. El archivo necesitará importar el arreglo COUNTRIES para poder tener acceso a los datos. De manera similar, el archivo tendrá que importar la clase Country para que todos los datos dentro del arreglo COUNTRIES tenga sentido.
También estaremos importando otras dependencias como Injectable desde el núcleo Angular para hacer a nuestra clase CountryService disponible para el inyector en otros componentes.
Una vez que tu aplicación crece, diferentes módulos necesitarán comunicarse entre ellos. Digamos que el ModuleA requiere a ModuleB para poder funcionar adecuadamente. En tales casos, llamaríamos a ModuleB una dependencia de ModuleA.
Simplemente importar el módulo que necesitamos a otro archivo funciona la mayoría del tiempo. Sin embargo, algunas veces necesitamos decidir si deberíamos crear una sola instancia de clases de ModuleB que será usada por toda la aplicación o si deberíamos crear una nueva instancia cada vez que el módulo es usado. En nuestro caso, estaremos inyectando una sola instancia de nuestra clase CountryService a lo largo de la aplicación.
Aquí está el código para country.service.ts:
1 |
import { Injectable } from '@angular/core'; |
2 |
|
3 |
import { Country } from './country'; |
4 |
import { COUNTRIES } from './country-data'; |
5 |
|
6 |
@Injectable() |
7 |
export class CountryService { |
8 |
|
9 |
constructor() { } |
10 |
|
11 |
getCountries(): Country[] { |
12 |
return COUNTRIES; |
13 |
}
|
14 |
|
15 |
getPopulatedCountries(): Country[] { |
16 |
return COUNTRIES.sort((a, b) => b.population - a.population).slice(0, 3); |
17 |
}
|
18 |
|
19 |
getLargestCountries(): Country[] { |
20 |
return COUNTRIES.sort((a, b) => b.area - a.area).slice(0, 3); |
21 |
}
|
22 |
|
23 |
getGDPCountries(): Country[] { |
24 |
return COUNTRIES.sort((a, b) => b.gdp - a.gdp).slice(0, 3); |
25 |
}
|
26 |
|
27 |
getCountry(name: string): Country { |
28 |
return COUNTRIES.find(country => country.name === name); |
29 |
}
|
30 |
}
|
Un decorador @injectable es usado para identificar una clase de servicio que podría requerir dependencias inyectadas. Sin embargo, agregar el @injectable a clases de servicio es un estilo de código requerido, así que lo hacemos de cualquier manera.
Después de eso, escribimos diferentes métodos para la clase la cuál toma el arreglo COUNTRIES y lo retorna directamente o acomoda usando cierto criterio y después devuelve una parte del arreglo.
El método getCountries() se espera que devuelva todos los objetos Country, y así devuelve todo el arreglo COUNTRIES sin hacerle ninguna modificación.
El getPopulatedCountries() toma el arreglo COUNTRIES y los acomoda en orden descendente basado en la población de diferentes países. Después usamos el método Array.slice() para poder devolver los primeros tres países (con índices 0, 1, y 2) desde el arreglo. Los métodos getLargestCountries() y getGDPCountries() funcionan de forma similar.
El método getCountry() toma un nombre y su argumento y devuelve el objeto país cuya propiedad nombre renga el mismo valor que el argumento de nombre suministrado.
Incluyendo CountryService en app.module.ts
Un servicio que creas es solo una clase en Angular hasta que lo tienes registrado con un inyector de dependencia Angular. Un inyector Angular será el responsable de crear instancias de servicio e inyectarlas a diferentes clases que necesiten ese servicio. Necesitamos registrar un servicio con un proveedor antes de que el inyector pueda crear ese servicio.
Hay dos maneras comunes de registrar cualquier servicio: usar un proveedor @Component o usar el proveedor @NgModule. Usar el proveedor @Component tiene sentido cuando quieres restringir el acceso de un servicio a un componente en particular y todos sus componentes anidados. Usar el proveedor @NgModule tiene sentido cuando quieres que múltiples componentes tengan acceso al servicio.
En nuestro caso, estaremos usando CountryService con múltiples componentes de nuestra aplicación. Esto significa que deberíamos registrarlo con el proveedor @NgModule una vez, en lugar de registrarlo de manera separada con el proveedor @Component de cada componente.
Actualmente, tu archivo app.module.ts debería lucir así:
1 |
import { BrowserModule } from '@angular/platform-browser'; |
2 |
import { NgModule } from '@angular/core'; |
3 |
|
4 |
import { AppComponent } from './app.component'; |
5 |
|
6 |
@NgModule({ |
7 |
declarations: [ |
8 |
AppComponent
|
9 |
],
|
10 |
imports: [ |
11 |
BrowserModule
|
12 |
],
|
13 |
providers: [], |
14 |
bootstrap: [AppComponent] |
15 |
})
|
16 |
|
17 |
export class AppModule { } |
Agrega una declaración de importación al archivo app.module.ts y agrega el servicio al arreglo de proveedores @NgModule. Después de hacer estos cambios, tu archivo app.module.ts debería lucir como esto:
1 |
import { BrowserModule } from '@angular/platform-browser'; |
2 |
import { NgModule } from '@angular/core'; |
3 |
|
4 |
import { AppComponent } from './app.component'; |
5 |
import { CountryService } from './country.service'; |
6 |
|
7 |
@NgModule({ |
8 |
declarations: [ |
9 |
AppComponent
|
10 |
],
|
11 |
imports: [ |
12 |
BrowserModule
|
13 |
],
|
14 |
providers: [CountryService], |
15 |
bootstrap: [AppComponent] |
16 |
})
|
17 |
export class AppModule { } |
La clase CountryService ahora estará disponible para todos los componentes que creamos para nuestra aplicación.
Conclusiones
Crear exitosamente tres archivos nombrados country.ts, country-data.ts, y country.service.ts concluye el segundo tutorial de esta serie.
El archivo country.ts es usado para crear una clase Country con diferentes propiedades como nombre, moneda, población área, etc. El archivo country.data.ts es usado para almacenar un arreglo de objetos de país el cuál tiene información sobre diferentes países. El archivo country.service.ts contiene una clase de servicio con diferentes métodos para acceder a la información del país desde el arreglo COUNTRIES. Escribir todos estos métodos de manera separada dentro de una clase de servicio nos permite acceder a ellos dentro de diferentes componentes de aplicación desde una ubicación central.
En la última sección, registramos nuestro servicio con el proveedor @NgModule para hacerlo disponible para usar dentro de diferentes componentes.
El siguiente tutorial te mostrará cómo crear tres componentes diferentes en tu aplicación para mostrar detalles de países y una lista de países.



