Beruflich Dokumente
Kultur Dokumente
Método Descripción
Encadenar() Este método devuelve una cadena que representa un número en base 10.
toString (2) toString (8) toString Este método devuelve una cadena que representa un número en binario, octal
(16) o hexadecimal.
toFixed (n) Este método devuelve una cadena que representa un número real con el
norte dígitos después del punto decimal.
toExponential (n) Este método devuelve una cadena que representa un número usando la notación
exponencial con un dígito antes del punto decimal y
norte dígitos después.
toPrecision (n) Este método devuelve una cadena que representa un número con norte
cifras significativas, usando la notación exponencial, si es necesario.
La técnica complementaria es la de convertir cadenas en números para que pueda realizar la suma en lugar de la concatenación. Puede hacer esto
con la Número función, como se muestra en el Listado 5-26 .
Resultado: 10
los Número función es estricta en el modo en que analiza los valores de cadena, pero hay otras dos funciones que puede utilizar que son
más flexibles y no hará caso de fuga caracteres no numéricos. Estas funciones son parseInt
y parseFloat. He descrito los tres métodos de la Tabla 5-5 .
Método Descripción
Número (str) Este método analiza la cadena especificada para crear un valor entero o real.
parseInt (str) Este método analiza la cadena especificada para crear un valor entero.
parseFloat (str) Este método analiza la cadena especificada para crear un valor entero o real.
80
Capítulo 5 ■ JavaScript y mecanografiado: parte 1
matriz.
Listado 5-27. Crear y llenar una matriz en el archivo main.ts en la carpeta src
He creado una nueva matriz llamando new Array (). Esto crea una matriz vacía, lo que le asigno a la variable miMatriz. En los
estados posteriores, I asignar valores a varias posiciones de índice en el array. (No hay salida de la consola de este listado.)
Hay un par de cosas para observar en este ejemplo. En primer lugar, yo no tenía necesidad de declarar el número de elementos en la matriz cuando lo creé.
matrices de JavaScript cambiarán de tamaño sí mismos para contener cualquier número de elementos. El segundo punto es que yo no tenía que declarar los tipos de datos
que contendrá la matriz. Cualquier matriz de JavaScript puede contener cualquier combinación de tipos de datos. En el ejemplo, he asignado tres elementos a la matriz:
booleano.
El estilo literal de Array le permite crear y rellenar una matriz en un solo estado, como se muestra en el Listado 5-28 .
Listado 5-28. Utilizando el literal de matriz estilo en el main.ts archivo en la carpeta src
En este ejemplo, he especificado que la miMatriz variable debe ser asignado una nueva matriz mediante la especificación de los elementos
que quería en la matriz entre corchetes ([y]). (No hay salida de la consola de este listado.)
Listado 5-29. La lectura de los datos de un índice de matriz en los main.ts archivo en la carpeta src
Puede modificar los datos contenidos en cualquier posición en una matriz de JavaScript simplemente mediante la asignación de un nuevo valor para el índice.
Al igual que con las variables regulares, puede cambiar el tipo de datos en un índice sin ningún problema. La salida de la lista es la siguiente:
El índice 0: 100
81
Capítulo 5 ■ JavaScript y mecanografiado: parte 1
Listado 5-30. Modificación del contenido de una matriz en el archivo main.ts en la carpeta src
En este ejemplo, he asignado una cuerda posicionar 0 en la matriz, una posición que se llevó a cabo anteriormente por una número y produce
esta salida:
El índice 0: Martes
Listado 5-31. Enumerando el contenido de una matriz en el archivo main.ts en la carpeta src
console.log ( "---");
el JavaScript para bucle funciona de la misma manera que los bucles en muchos otros idiomas. A determinar cuántos elementos hay en la
matriz mediante el uso de la longitud propiedad.
La función pasa a la para cada método se da dos argumentos: el valor del elemento actual sea procesada y la posición de
ese elemento de la matriz. En este listado, he utilizado una función de la flecha como el argumento de la para cada método, que es
el tipo de uso para el que se destacan (y verá utilizado a lo largo de este libro). La salida de la lista es la siguiente:
El índice 0: 100
Índice 1: Índice de
Adam 2: true
El índice 0: 100
Índice 1: Índice de
Adam 2: true
82
Capítulo 5 ■ JavaScript y mecanografiado: parte 1
otras matrices. en el Listado 5-32 , He usado el operador de difusión para ampliar una matriz de modo que sus elementos se pueden combinar en otra matriz.
Listado 5-32. Uso del spread en las main.ts archivo en la carpeta src
El operador propagación es una elipsis (una secuencia de tres periodos), y hace que la matriz para ser desempaquetado.
...
dejar que otherArray = [... miMatriz, 200, "Bob", false];
...
Usando el operador de difusión, soy capaz de especificar miMatriz como un elemento cuando defino otherArray, con el resultado de que el contenido
de la primera matriz se descomprime y se añaden como los artículos a la segunda matriz. Este ejemplo produce los siguientes resultados:
el JavaScript Formación objeto define una serie de métodos que se pueden utilizar para trabajar con matrices, los más útiles de los cuales se
83
Capítulo 5 ■ JavaScript y mecanografiado: parte 1
Método Descripción
concat (otherArray) Este método devuelve una nueva matriz que concatena la matriz en la que se le ha llamado con la
matriz especificada como argumento. Varias matrices se pueden especificar.
join (separador) Este método se une a todos los elementos de la matriz para formar una cadena. El argumento
especifica el carácter utilizado para delimitar los elementos.
marcha atrás() Este método devuelve una nueva matriz que contiene los artículos en orden inverso.
ordenar() Este método clasifica la matriz. Una función de comparación opcional se puede utilizar para realizar
comparaciones personalizados.
empalme (índice, recuento) Este método elimina contar elementos de la matriz, a partir de la especificada
índice. Los elementos retirados se devuelven como el resultado del método.
cada (prueba) Este método llama al prueba función para cada elemento de la matriz y vuelve
cierto Si la función devuelve cierto para todos ellos, y en caso contrario.
algunos (de prueba) Este método devuelve cierto si llama la prueba función para cada elemento de los retornos de matriz cierto al
menos una vez.
filtro (test) Este método devuelve una nueva matriz que contiene los artículos para los que el prueba
devuelve la función cierto.
encontrar (prueba) Este método devuelve el primer elemento de la matriz para la cual el prueba
devuelve la función cierto.
FindIndex (test) Este método devuelve el índice del primer elemento de la matriz para la cual el
prueba devuelve la función cierto.
foreach (devolución de llamada) Este método invoca el llamar de vuelta función para cada elemento de la matriz, como se describe en la
sección anterior.
incluye (valor) Este método devuelve cierto Si la matriz contiene el valor especificado.
Mapa (devolución de llamada) Este método devuelve una nueva matriz que contiene el resultado de la invocación de la
reducir (devolución de llamada) Este método devuelve el valor acumulado producido mediante la invocación de la función de devolución de
84
Capítulo 5 ■ JavaScript y mecanografiado: parte 1
Dado que muchos de los métodos de la Tabla 5-6 devolver una nueva matriz, estos métodos se pueden encadenar juntos para procesar una matriz de datos de
Listado 5-33. Procesamiento de una matriz de datos en el archivo main.ts en la carpeta src
deje productos = [
{Name: "sombrero", precio: 24,5, de almacén: 10}, {nombre: "Kayak",
precio: 289.99, existencia: 1}, {nombre: "Balón de fútbol", precio: 10,
existencia: 0}, { nombre: "zapatillas deportivas", precio: 116.50, Stock: 20}];
Yo uso el filtrar Método para seleccionar los elementos de la matriz cuyos valores valor es mayor que cero y el uso de la reducir método para
determinar el valor total de esos artículos, produciendo el resultado siguiente:
Resumen
En este capítulo, he proporcionado un breve panorama sobre el código JavaScript, centrándose en la funcionalidad básica que le ayudará a comenzar con el
lenguaje. Algunas de las características que he descrito en este capítulo son las últimas adiciones a la especificación JavaScript y requieren el compilador de
transcripción de la convierte en el código que se puede ejecutar en los navegadores antiguos. Sigo este tema en el siguiente capítulo y presento algunas de las
características más avanzadas de JavaScript que se utilizan en el desarrollo angular.
85
CAPÍTULO 6
En este capítulo, se describen algunas de las características más avanzadas de JavaScript que son útiles para el desarrollo angular. Explico cómo
ofertas de JavaScript con objetos, incluido el apoyo para las clases, y explico como la funcionalidad de JavaScript se envasa en módulos de
JavaScript. También les presento algunas de las características que ofrece mecanografiado que no forman parte de la especificación JavaScript y
que me baso en algunos de los ejemplos más adelante en el libro. Mesa 6-1 resume el capítulo.
Crear un objeto especificando propiedades y valores Utilizar el nuevo Palabra clave o utilizar un objeto 1-3
literal
Declarar los tipos utilizados por las propiedades, parámetros y variables Uso mecanografiado anotaciones de tipo 13-18
Control de acceso a los métodos y propiedades de una clase de uso de los modificadores de control de acceso 24
Una nueva ventana del navegador se abrirá, pero será vacío porque me quita el contenido marcador de posición en el capítulo anterior. Los
ejemplos de este capítulo se basan en la consola JavaScript del navegador para mostrar los mensajes. Si nos fijamos en la consola, verá el siguiente
resultado:
■ Nota Algunos de los ejemplos de este capítulo que el compilador mecanografiado para informar errores. los ejemplos siguen trabajando, y se puede
ignorar estos mensajes, que surgen a causa mecanografiado ofrece algunas características adicionales que no describo hasta más adelante en este
capítulo.
Creo un objeto llamando new Object (), y asignar el resultado (el objeto recién creado) a una variable llamada mis datos. Una vez que se crea el
objeto, puedo definir las propiedades del objeto, simplemente mediante la asignación de valores, como este:
...
mis datos. name = " Adán";
...
Antes de esta declaración, mi objeto no tiene una propiedad llamada nombre. Cuando la declaración ha ejecutado, la propiedad
existe, y se le ha asignado el valor Adán. Puede leer el valor de una propiedad mediante la combinación del nombre de la variable y el
nombre de la propiedad con un punto, como esto:
...
console.log ( "Hola" + myData.name +) "";
...
88
Capítulo 6 ■ JavaScript y mecanografiado: parte 2
Listado 6-2. Uso del objeto Formato literal en el main.ts archivo en la carpeta src
nombre: "Adán",
tiempo: "soleado"};
Cada propiedad que desea definir se separa de su valor con dos puntos (:), y las propiedades se separan mediante una
coma (,). El efecto es el mismo que en el ejemplo anterior, y el resultado de la lista es la siguiente:
Listado 6-3. Adición de métodos para un objeto en el main.ts archivo en la carpeta src
};
myData.printMessages ();
En este ejemplo, he utilizado una función para crear un método llamado printMessages. Observe que para referirse a las propiedades definidas
por el objeto, tengo que utilizar el esta palabra clave. Cuando una función se utiliza como método, la función se pasa implícitamente el objeto sobre el
cual el método ha sido llamado como un argumento a través de la variable especial esta. La salida de la lista es la siguiente:
89
Capítulo 6 ■ JavaScript y mecanografiado: parte 2
Definición de clases
Las clases son plantillas que se utilizan para crear objetos que tienen una funcionalidad idéntica. El apoyo a las clases es una adición reciente a
la especificación JavaScript destinada a facilitar el trabajo con JavaScript más coherente con otros lenguajes de programación convencionales, y
las clases se utiliza en todo el desarrollo angular. Listado 6-4 muestra cómo la funcionalidad definida por el objeto en la sección anterior se puede
expresar utilizando una clase.
Class MiClase {
printMessages () {
console.log ( "Hola" + this.name + ""); console.log ( "Hoy en día
es" + this.weather + ""); }}
clases de JavaScript será familiar si ha usado otro lenguaje corriente, como Java o C #. los clase palabra clave se utiliza para
declarar una clase, seguido del nombre de la clase, que es Mi clase en este caso.
los constructor función se invoca cuando se crea un nuevo objeto utilizando la clase, y ofrece la oportunidad de recibir los valores de
datos y realice una configuración inicial de que la clase requiere. En el ejemplo, el constructor define nombre y clima parámetros que se utilizan
para crear variables con los mismos nombres. Las variables definidas como esto se conocen como propiedades.
Las clases pueden tener métodos, que definen como funciones, aunque sin necesidad de utilizar la palabra clave función. Hay un
método en el ejemplo, se llama printMessages, y utiliza los valores de la name and
weather propiedades para escribir mensajes a la consola JavaScript del navegador.
■ Propina Las clases también pueden tener métodos estáticos, designados por el estático palabra clave. Los métodos estáticos pertenecen a la clase en
lugar de los objetos que crean. he incluido un ejemplo de un método estático en el Listado 6-14 .
los nuevo palabra clave se utiliza para crear un objeto de una clase, de esta manera:
...
dejar que myData = nuevo MiClase ( "Adam", "sol");
...
Esta sentencia crea un nuevo objeto con el Mi clase clase como su plantilla. Mi clase se utiliza como una función en esta situación, y los
argumentos que se le pasan serán recibidos por el constructor función definida por la clase. El resultado de esta expresión es un nuevo objeto
que se asigna a una variable llamada mis datos.
Una vez que haya creado un objeto, puede acceder a sus propiedades y métodos a través de la variable a la que se le ha asignado,
así:
90
Capítulo 6 ■ JavaScript y mecanografiado: parte 2
...
myData. printMessages ();
...
Este ejemplo produce los siguientes resultados en la consola JavaScript del navegador:
el rasgo de clase no cambia la forma subyacente que maneja JavaScript tipos. En su lugar, simplemente proporciona una manera de utilizar
los que es más familiar para la mayoría de los programadores. Detrás de las escenas, JavaScript sigue utilizando su sistema de tipo
tradicional, que se basa en prototipos. como un ejemplo, el código del listado 6-4 También se puede escribir así:
MyClass.prototype.printMessages = function () {
console.log ( "Hola" + this.name + ""); console.log ( "Hoy en día
es" + this.weather + ""); };
desarrollo angular es más fácil cuando el uso de clases, que es el enfoque que he tomado a lo largo de este libro. muchas de las
características introducidas en ES6 se clasifican como azúcar sintáctico, lo que significa que hacen aspectos de JavaScript más fáciles de
entender y utilizar. el termino azúcar sintáctica puede parecer peyorativo, pero JavaScript tiene algunas peculiaridades impares, y muchas de
clases JavaScript pueden definir las propiedades en su constructor, lo que resulta en una variable que se puede leer y modificar otras partes de la
aplicación. Captadores y definidores aparecen propiedades como regulares fuera de la clase, pero permiten la introducción de una lógica adicional, que
es útil para la validación o la transformación de nuevos valores o generar valores de programación, como se muestra en el Listado 6-5 .
91
Capítulo 6 ■ JavaScript y mecanografiado: parte 2
Listado 6-5. El uso de captadores y definidores en los main.ts archivo en la carpeta src
Class MiClase {
constructor (nombre, tiempo) {
this.name = nombre;
this._weather = tiempo;
}
this._weather = valor; }
printMessages () {
console.log ( "Hola" + this.name + "");
console.log (this.weather);
}}
El getter y setter se implementan como funciones precedidas por el obtener o conjunto palabra clave. No existe la noción de control de acceso en
las clases de JavaScript, y la convención es como prefijo para los nombres de las propiedades internas con un guión bajo (_ el personaje). En el perfil,
la clima la propiedad se implementa con un colocador que actualiza una propiedad llamada _ clima y un captador que incorpora el _ clima valor en una
cadena de plantilla. Este ejemplo produce los siguientes resultados en la consola JavaScript del navegador:
Las clases pueden heredar el comportamiento de otras clases utilizando el se extiende palabra clave, como se muestra en el Listado 6-6 .
Class MiClase {
constructor (nombre, tiempo) {
this.name = nombre;
this._weather = tiempo; }
92
Capítulo 6 ■ JavaScript y mecanografiado: parte 2
printMessages () {
console.log ( "Hola" + this.name + ""); console.log
(this.weather); }}
printMessages () {
super.printMessages ();
console.log ( `Usted está en $ {}` this.city); }}
los se extiende palabra clave se utiliza para declarar la clase que será heredado de, conocido como el superclase
o clase base. En el perfil, la MySubClass hereda de Mi clase. los súper palabra clave se utiliza para invocar el constructor y los métodos de la
superclase. los MySubClass se basa en la Mi clase funcionalidad para añadir soporte para una ciudad, produciendo los siguientes resultados en la
consola JavaScript del navegador:
■ Nota Las versiones anteriores de angular se basó en un cargador de módulos, lo que enviaría solicitudes HTTP independiente para los archivos
JavaScript requeridos por una aplicación. Los cambios en las herramientas de desarrollo han simplificado este proceso y cambiar al uso de los paquetes
93
Capítulo 6 ■ JavaScript y mecanografiado: parte 2
obtener nameMessage () {
retorno `Hola $ {} $ this.first {}` this.second; }}
obtener weatherMessage () {
volver `Es $ {} this.weather en $ {}` this.city; }}
Las clases, funciones y variables definidas en un fichero de transcripción JavaScript o sólo se puede acceder dentro de ese archivo por defecto.
los exportar palabra clave se utiliza para realizar funciones accesibles fuera del archivo para que puedan ser utilizados por otras partes de la aplicación.
En el ejemplo, he aplicado la exportar palabra clave para la
Nombre y WeatherLocation clases, lo que significa que están disponibles para ser utilizados fuera del módulo.
■ Propina he definido dos clases en el NameAndWeather.ts archivo, que tiene el efecto de crear un módulo que contiene dos clases. la
convención en aplicaciones angulares es poner cada clase en su propio archivo, lo que significa que cada clase se define en su propio
módulo y que verá el exportar palabra clave es los anuncios a lo largo de este libro.
los importar palabra clave se utiliza para declarar una dependencia de las características que ofrece un módulo. en el Listado 6-8 , He utilizado Nombre
y WeatherLocation clases en el main.ts Archivo y eso significa que tengo que usar el importar palabra clave para declarar una dependencia de ellos y el
módulo del que proceden.
94
Capítulo 6 ■ JavaScript y mecanografiado: parte 2
console.log (name.nameMessage);
console.log (loc.weatherMessage);
Esta es la forma en que utilizo el importar palabra clave en la mayoría de los ejemplos de este libro. La palabra clave es seguido por llaves que
contienen una lista separada por comas de las características que el código en los archivos actuales depende, seguido por el desde palabra clave, seguido
por el nombre del módulo. En este caso, he importado el
Nombre y WeatherLocation clases de la NameAndWeather en el módulo módulos carpeta. Observe que la extensión del archivo no se incluye
cuando se especifica el módulo.
Cuando los cambios en el main.ts archivos se guardan, las herramientas de desarrollo angular construir el proyecto y ver que el código en el main.ts
de archivo depende del código de la NameAndWeather.ts expediente. Esta dependencia asegura que la Nombre y WeatherLocation las clases se
incluyen en el archivo de paquete de JavaScript, y verá la siguiente salida en la consola de JavaScript del navegador, lo que demuestra que el código
en el módulo se utilizó para producir el resultado:
Tenga en cuenta que yo no tenía para incluir el NaneAndWeather.ts archivo en una lista de archivos que se envía al navegador. Sólo mediante el importar
palabra clave es suficiente para declarar la dependencia y asegurar que el código requerido por la aplicación se incluye en el archivo JavaScript enviado al
navegador.
(Podrá ver los errores que le advierte de que las propiedades no se han definido haga caso de las advertencias por ahora;.. Me explico cómo
se resuelven más adelante en el capítulo)
verá dos maneras diferentes de la especificación de los módulos en el importar declaraciones de este libro. el primero es un módulo
relativo, en el que el nombre del módulo se prefija con ./, como en este ejemplo de la lista 6-8 :
...
{Nombre importación, WeatherLocation} de" ./ módulos / NameAndWeather ";
...
esta declaración especifica un módulo situado en relación con el archivo que contiene la importar declaración. en este caso, el NameAndWeather.ts archivo
main.ts expediente. El otro tipo de importación es no relativa. aquí es un ejemplo de una importación que no es pariente del capítulo 2 y uno
...
{} la importación de componentes de "@ angular / núcleo ";
...
el módulo en este importar declaración no se inicia con ./, y las herramientas de construcción resolver la dependencia mediante la búsqueda de
un paquete en el node_modules carpeta. en este caso, la dependencia está en una característica proporcionada por el @ angular / núcleo paquete,
95
Capítulo 6 ■ JavaScript y mecanografiado: parte 2
En proyectos complejos que tienen un montón de dependencias, es posible que usted tendrá que utilizar dos clases con el mismo nombre de diferentes
módulos. Para volver a crear esta situación, he creado un archivo llamado DuplicateName.ts
en el src / modules carpeta y se define la clase de muestra en el listado 6-9 .
conocer el mensaje () {
Esta clase no hace nada útil, pero se llama Nombre, lo que significa que la importación se aplique el método del inmueble 6-8 causará un
conflicto porque el compilador no será capaz de diferenciar entre las dos clases con ese nombre. La solución es utilizar la como palabra clave,
que permite un alias a ser creado para una clase cuando se importa desde un módulo, como se muestra en el listado 6-10 .
console.log (name.nameMessage);
console.log (loc.weatherMessage);
console.log (other.message);
los Nombre clase en el DupliateName módulo se importa como Otro nombre, lo que permite que sea utilizado sin entrar en conflicto con el Nombre
clase en el NameAndWeather módulo. En este ejemplo se produce el siguiente resultado:
Un enfoque alternativo es importar el módulo como un objeto que tiene propiedades para cada uno de los tipos que contiene, como se muestra en el
Listado 6-11 .
Listado 6-11. La importación de un módulo como un objeto en el archivo main.ts en la carpeta src
96
Capítulo 6 ■ JavaScript y mecanografiado: parte 2
dejar que name = nueva NameAndWeatherLocation.Name ( "Adam", "Freeman"); dejar que loc = new
NameAndWeatherLocation.WeatherLocation ( "llover", "Londres");
dejar que otra nueva otherName = ();
console.log (name.nameMessage);
console.log (loc.weatherMessage);
console.log (other.message);
los importar declaración en este ejemplo se importa el contenido de la NameAndWeather módulo y crea un objeto llamado NameAndWeatherLoca
Este objeto tiene Nombre y Clima propiedades que corresponden a las clases definidas en el módulo. Este ejemplo produce la misma
salida que Listado 6-10 .
■ Propina mecanografiado soporta más características que describo en este capítulo. Me presento algunas características adicionales como los utilizo en
capítulos posteriores, pero para una referencia completa, consulte la página mecanografiada a casa a las www.typescriptlang.org.
La característica titular mecanografiado es el soporte para anotaciones de tipos, que pueden ayudar a reducir los errores comunes de JavaScript mediante la
aplicación de comprobación de tipos al compilar el código, de una manera que es una reminiscencia de lenguajes como C # o Java. Si ha tenido problemas para
ponerse de acuerdo con el sistema de tipos JavaScript (o incluso no darse cuenta de que había uno), a continuación, escriba anotaciones puede recorrer un largo
camino para la prevención de los errores más comunes. (Por otro lado, si te gusta la libertad de los tipos de JavaScript regulares, es posible que el tipo
mecanografiado advertencias restrictivas y molesto.)
Para mostrar el tipo de problema que resuelven las anotaciones tipo, he creado un archivo llamado tempConverter.ts en el
JavaScriptPrimer carpeta y añade el código del listado 6-12 .
los TempConverter clase contiene un método estático simple llamado convertFtoC que acepta un valor de la temperatura expresada en
grados Fahrenheit y devuelve la misma temperatura expresada en grados Celsius.
97
Capítulo 6 ■ JavaScript y mecanografiado: parte 2
Hay supuestos en este código no explícitos. los convertFtoC método espera para recibir una número valor, en la que el toPrecision método
se llama para establecer el número de dígitos de coma flotante. El método devuelve un cuerda, aunque eso es difícil de decir sin
inspeccionar el código cuidadosamente (el resultado de la toFixed método es una cuerda).
Estas suposiciones implícitas conducen a problemas, especialmente cuando un desarrollador está utilizando código JavaScript escrito por otro.
en el Listado 6-13 , He creado deliberadamente un error al pasar la temperatura como una
cuerda valor, en lugar de la número que el método espera.
Listado 6-13. Utilizando el tipo incorrecto de los main.ts archivo en la carpeta src
Cuando el código es ejecutado por el navegador, aparecerá el siguiente mensaje en la consola de JavaScript del navegador (el
funcionamiento exacto puede variar en función del navegador que esté utilizando):
Este tipo de problema se puede solucionar sin necesidad de utilizar mecanografiado, por supuesto, pero sí significa que una cantidad sustancial del
código JavaScript en cualquier aplicación está dedicada a la comprobación de los tipos que se están utilizando. La solución mecanografiado es hacer que la
aplicación de tipo el trabajo del compilador, usando anotaciones de tipos que se agregan al código JavaScript. en el Listado 6-14 , He añadido anotaciones de
tipo a la TempConverter clase.
anotaciones de tipo se expresan utilizando dos puntos (el: carácter), seguido por el tipo. Hay dos anotaciones en el ejemplo.
El primero especifica que el parámetro a la convertFtoC método debe ser una
número.
...
estática convertFtoC (temp: número): cuerda {
...
98
Capítulo 6 ■ JavaScript y mecanografiado: parte 2
...
estática convertFtoC (temp: número): cuerda {
...
Al guardar los cambios en el archivo, el compilador mecanografiado se ejecutará. Entre los errores que se denuncian será la siguiente:
El compilador mecanografiado ha examinado que el tipo del valor pasa a la convertFtoC método en el main.ts archivo no coincide con el
tipo de anotación y se ha informado de un error. Este es el núcleo del sistema de tipo Letra de imprenta; esto significa que usted no tiene que
escribir código adicional en sus clases para comprobar que ha recibido los tipos esperados, y también hace que sea fácil de determinar el tipo
de resultado método. Para resolver el error reportado para el compilador, de venta 6-15 actualiza la declaración que invoca el convertFtoC
dejar que name = Nombre nuevo ( "Adam", "Freeman"); dejar que loc = new
WeatherLocation ( "llover", "Londres"); dejar que otra nueva otherName = ();
console.log (name.nameMessage);
console.log (loc.weatherMessage);
console.log (other.message);
console.log ( `La temperatura es $ {} cTemp C ');
Al guardar los cambios, verá los siguientes mensajes que aparecen en la consola de JavaScript del navegador:
La temperatura es 3.3C
99
Capítulo 6 ■ JavaScript y mecanografiado: parte 2
primera cuerda;
segunda cuerda;
Las propiedades se declaran con una anotación de tipo, siguiendo el mismo patrón como para los parámetros y resultados anotaciones. Los
cambios en el Listado 6-17 resolver los errores restantes reportados por el compilador mecanografiado, que se quejaba porque no sabía lo que eran los
tipos de las propiedades creadas en los constructores.
El patrón de recibir parámetros del constructor y la asignación de sus valores a las variables es tan común que mecanografiado incluye una
optimización, como se muestra en el Listado 6-17 .
Listado 6-17. Utilización de parámetros en los NameAndWeather.ts archivo en la carpeta src / modules
100
Capítulo 6 ■ JavaScript y mecanografiado: parte 2
la palabra clave privado es un ejemplo de un modificador de control de acceso, que describo en la sección “Uso de Modificadores de acceso”. La
aplicación de la palabra clave para el parámetro constructor tiene el efecto de definir automáticamente la propiedad de clase y asignarle el valor del
parámetro. El código del Listado 6-17 es una versión más concisa del Listado 6-16 .
Mecanografiado permite que varios tipos que se especificarán, separada por medio de una barra (el carácter |). Esto puede ser útil cuando un método
puede aceptar o devolver varios tipos o cuando una variable se puede valores de diferentes tipos asignado. Listado 6-18 modifica la convertFtoC método
por lo que aceptará número o cuerda valores.
Listado 6-18. Aceptar varios valores en los tempConverter.ts archivo en la carpeta src
los tipo Declaración para el temperatura parámetro tiene cambios en número | cuerda, lo que significa que el método puede aceptar cualquiera de
los valores. Esto se llama una tipo de unión. Dentro del método, una afirmación de tipo se utiliza para averiguar qué tipo ha sido recibido. Este es un
proceso algo torpe, pero el valor del parámetro es echada a un valor de número para comprobar si hay una toPrecision método definido en el resultado,
como este:
...
Los corchetes angulares (los caracteres <y>) son para declarar una afirmación de tipo, que se tratará de convertir un objeto al tipo especificado. También
puede obtener el mismo resultado utilizando el como palabra clave, como se muestra en el Listado 6-19 .
Listado 6-19. El uso de la palabra clave en el que tempConverter.ts archivo en la carpeta src
101
Capítulo 6 ■ JavaScript y mecanografiado: parte 2
En lugar de especificar un tipo de unión es el uso de la alguna palabra clave, que permite a cualquier tipo que se asigna a una variable, utilizado
como un argumento, o volvió de un método. Listado 6-20 sustituye al tipo de unión en el
convertFtoC método con el alguna palabra clave.
■ Propina el compilador mecanografiado implícitamente aplicar el alguna palabra clave cuando se omite una anotación de tipo.
valor = 0; }
El uso de tuplas
Las tuplas son matrices de longitud fija, donde cada elemento de la matriz es de un tipo especificado. Esta es una descripción de sonido vago porque tuplas
son tan flexibles. A modo de ejemplo, el listado 6-21 utiliza una tupla para representar una ciudad y su clima y la temperatura actual.
102
Capítulo 6 ■ JavaScript y mecanografiado: parte 2
Las tuplas se definen como una matriz de tipos, y se accede a los elementos individuales usando indizadores de matriz. Este ejemplo produce el
siguiente mensaje en la consola de JavaScript del navegador:
Listado 6-22. Uso de tipos de indexables en los main.ts archivo en la carpeta src
los ciudades variable se define como un tipo indexable, con la tecla como una cadena y el valor de datos como un [ cadena, cadena] tupla. Los
valores se asignan y se leen utilizando indizadores de estilo de matriz, tales como
ciudades [ "Londres"]. La colección de teclas en un tipo orientable se puede acceder mediante una for ... in bucle, como se muestra en el
ejemplo, que produce la siguiente salida en la consola JavaScript del navegador:
Solamente número y cuerda Los valores se pueden utilizar como las teclas de tipos indexables, pero esto es una característica muy útil que utilizo en los ejemplos
JavaScript no es compatible con la protección de acceso, lo que significa que las clases, sus propiedades y sus métodos pueden ser accedidos desde
cualquier parte de la aplicación. Hay una convención de prefijar el nombre de los miembros de implementación con un guión bajo (_ el personaje), pero
esto es sólo una advertencia a otros desarrolladores y no se cumple.
Mecanografiado proporciona tres palabras clave que se utilizan para gestionar el acceso y que son impuestas por el compilador. Mesa 6-2 describe
103
Capítulo 6 ■ JavaScript y mecanografiado: parte 2
■ Precaución durante el desarrollo, estas palabras clave tienen un efecto limitado en aplicaciones angulares debido a que una gran cantidad de
funcionalidad se entrega a través de propiedades y métodos que se especifican en fragmentos de código incrustados en las expresiones de enlace de
datos. estas expresiones se evalúan en tiempo de ejecución en el navegador, donde no hay una aplicación de características mecanografiado. que se
vuelven más importantes cuando se llega a implementar la aplicación, y es importante asegurarse de que cualquier propiedad o método que se accede
en una expresión de enlace de datos se marca como público o no tiene ningún modificador de acceso (que tiene el mismo efecto que el uso de la público palabra
clave).
público Esta palabra clave se utiliza para referirse a una propiedad o un método que se puede acceder en cualquier lugar. Se trata de la
privado Esta palabra clave se utiliza para denotar una propiedad o método que se puede acceder sólo dentro de la clase que lo
define.
protegido Esta palabra clave se utiliza para denotar una propiedad o método que se puede acceder sólo dentro de la clase que lo define o
por las clases que se extienden esa clase.
Listado 6-23. El uso de un modificador de acceso en los tempConverter.ts archivo en la carpeta src
valor = 0; }
los performCalculation método está marcado como privado, lo que significa que el compilador mecanografiado informará de un código de error
si cualquier otra parte de la aplicación intenta invocar el método.
104
Capítulo 6 ■ JavaScript y mecanografiado: parte 2
Resumen
En este capítulo, he descrito la forma en que es compatible con JavaScript trabajar con objetos y clases, explicó cómo funciona módulos de JavaScript, y
presenté las características mecanografiado que son útiles para el desarrollo angular. En el siguiente capítulo, comienzo del proceso de creación de un proyecto
realista que ofrece una visión general de cómo las diferentes características angulares trabajan juntos para crear aplicaciones antes de excavar en los detalles
individuales en la Parte 2 de este libro.
105
CAPÍTULO 7
en el capítulo 2 , He construido una aplicación angular rápido y sencillo. ejemplos pequeñas y enfocadas me permiten mostrar las características angular
específica, pero pueden carecer de contexto. Para ayudar a superar este problema, voy a crear una aplicación de comercio electrónico sencilla pero realista.
Mi aplicación, denominada SportsStore, seguirá el enfoque clásico tomada por las tiendas en línea de todo el mundo. Voy a crear un catálogo de
productos en línea que los clientes pueden navegar por categorías y la página, un carro de compras donde los usuarios pueden añadir y eliminar los
productos, y un check out donde los clientes pueden introducir sus detalles del envío y poner sus órdenes. También voy a crear una zona de administración
que incluye crear, leer, actualizar y eliminar instalaciones (CRUD) para la gestión del catálogo y lo protegerá de manera que sólo los administradores
registrados en pueden hacer cambios. Por último, os muestro cómo preparar y distribuir una aplicación angular.
Mi objetivo en este capítulo y las que siguen es para darle una idea de lo verdadero desarrollo angular es como mediante la creación de lo más
realista un ejemplo posible. Me quiero centrar en angular, por supuesto, y por lo que he simplificado la integración con sistemas externos, como el
almacén de datos, y otros omitido por completo, tales como el procesamiento de pagos.
El ejemplo SportsStore es uno que utilizo en algunos de mis libros, no menos importante, ya que demuestra la forma en que los
diferentes marcos, idiomas y estilos de desarrollo se pueden utilizar para conseguir el mismo resultado. No es necesario haber leído alguno de
mis otros libros seguir este capítulo, pero se puede encontrar los contrastes interesante si usted ya tiene mi Pro Core ASP.NET MVC 2 libro, por
ejemplo.
Las características angular que uso en la aplicación SportsStore están cubiertos en profundidad en capítulos posteriores. En lugar de duplicar
todo aquí, te digo lo suficiente para dar sentido a la aplicación de ejemplo y hacen referencia a otros capítulos para obtener información en
profundidad. Se pueden leer los capítulos SportsStore de extremo a extremo para tener una idea de cómo funciona o salto hacia y desde los
capítulos detalle angular para entrar en la profundidad. De cualquier manera, no esperes entender todo de inmediato-angular tiene una gran
cantidad de partes móviles, y la aplicación SportsStore está destinado a mostrar cómo encajan entre sí sin bucear demasiado en los detalles que me
paso el resto del libro que describe .
ng nuevo SportsStore
los angular-cli paquete creará un nuevo proyecto para el desarrollo angular, con los archivos de configuración, contenido marcador de posición, y
herramientas de desarrollo. El proceso de configuración del proyecto puede tomar algún tiempo, ya que hay muchos paquetes de NGP para descargar e instalar.
■ Propina Puede descargar el proyecto de ejemplo para este capítulo, y para todos los demás capítulos de este libro: de https://github.com/Apress/pro-angula
.
Se requieren paquetes adicionales para el proyecto SportsStore, además de los paquetes angular del núcleo y construir herramientas establecidas
por el ng nueva mando. Ejecute los siguientes comandos para navegar a la carpeta SportsStore y añadir los paquetes requeridos:
cd SportsStore
NPM instalar bootstrap@4.1.1 NPM instalar
font-awesome@4.7.0
NPM instalar --save-dev json-server@0.12.1 NPM instalar
--save-dev jsonwebtoken@8.1.1
Es importante utilizar los números de versión que aparecen en la lista. Es posible que vea advertencias acerca de las dependencias no satisfechas
por pares a medida que agrega los paquetes, pero se puede ignorar. Algunos de los paquetes se instalan mediante el - save-dev argumento, lo que indica
que se utilizan durante el desarrollo y no serán parte de la aplicación SportsStore.
Una vez que se han instalado los paquetes, añadir las declaraciones que aparecen en el listado 7-1 al angular.json presentar para incorporar los archivos
CSS desde el marco Bootstrap CSS y los paquetes de fuentes impresionantes en la aplicación. Voy a utilizar los estilos CSS Bootstrap para todo el
contenido HTML en la aplicación SportsStore, y utilizar los iconos del paquete impresionante fuente de presentar un resumen de un carrito de la compra
para el usuario.
...
"Arquitecto": {
"construir": {
"Builder": "@ angular DevKit / build-angular: el navegador", "opciones": {
"estilos": [
"Src / styles.css",
"Node_modules / bootstrap / dist / css / bootstrap.min.css", "node_modules
/ font-awesome / css / font-awesome.min.css"
],
108
Capítulo 7 ■ SportSStore: una aplicación real
"guiones": [] },
...
...
"guiones": { "ng":
"NG",
"Inicio": "ng sirven", "construir":
"ng acumulación", "prueba":
"prueba ng", "pelusa": "ng
pelusa", "E2E": "ng E2E",
Para proporcionar la JSON-servidor paquete con datos para trabajar, he añadido un archivo llamado data.js en el
Tienda de deportes carpeta y añade el código de muestra en el listado 7-3 , Que se asegurará de que el mismo se dispone de datos cada vez que el JSON-servidor
paquete se inició de modo que tenga un punto fijo de referencia durante el desarrollo.
■ Propina es importante prestar atención a los nombres de archivo al crear los archivos de configuración. Algunos tienen la
. JSON extensión, que significa que contienen datos estáticos con formato JSON. otros archivos tienen la extensión. js extensión, lo que significa que
contienen el código JavaScript. cada herramienta necesaria para el desarrollo angular tiene expectativas sobre su archivo de configuración.
module.exports = function () {
regreso {
los productos [
{Id: 1, nombre: "Kayak", categoría: "deportes acuáticos",
Descripción: "Un barco para una persona", precio: 275}, {id: 2, nombre:
"chaleco salvavidas", categoría: "deportes acuáticos",
Descripción: "Protección y de moda", precio: 48,95}, {id: 3, nombre: "Balón de
fútbol", categoría: "fútbol",
Descripción: "aprobado por la FIFA tamaño y peso", precio: 19,50}, {id: 4, nombre:
"banderas de la esquina", categoría: "fútbol",
109
Capítulo 7 ■ SportSStore: una aplicación real
pedidos: [] } }
Este código define dos colecciones de datos que serán presentados por el servicio web REST. los productos
colección contiene los productos para la venta al cliente, mientras que el pedidos colección contendrá las órdenes que los clientes han depositado
(pero que está actualmente vacía).
Los datos almacenados por el servicio web REST necesita ser protegido de manera que los usuarios normales no pueden modificar los productos o
cambiar el estado de los pedidos. los JSON-servidor paquete no incluye ningún características de autenticación incorporados, así que creé un archivo
llamado authMiddleware.js en el Tienda de deportes carpeta y añade el código del listado 7-4 .
res.end ();
regreso;
} Else if ((((( "req.url.startsWith / API / productos")
|| req.url.startsWith ( "/") productos) ||
(req.url.startsWith ( "/ API / categorías")
|| req.url.startsWith ( "/" categorías))) && req.method! = "GET") || ((( "req.url.startsWith /
API / órdenes")
110
Capítulo 7 ■ SportSStore: una aplicación real
res.statusCode = 401;
res.end (); regreso; }
siguiente(); }
Este código inspecciona las peticiones HTTP enviadas al servicio web REST y pone en práctica algunas de las características básicas de seguridad. Este es el
código del lado del servidor que no está directamente relacionado con el desarrollo angular, por lo que no se preocupe si su propósito no es inmediatamente evidente.
Explico el proceso de autenticación y autorización en el capítulo 9 , Incluyendo cómo autenticar a los usuarios angular.
■ Precaución No utilice el código del listado 7-4 excepto para la aplicación SportsStore. que contiene las contraseñas débiles que están cableados en el
código. esto está muy bien para el proyecto SportsStore porque el énfasis está en el lado del cliente con el desarrollo angular, pero esto no es adecuado
<Meta name = "viewport" content = "width = dispositivo de ancho, inicial escala = 1"> <rel = "icono" type
= "image / x-icon" enlace href = "favicon.ico"> </ head >
</ Html>
111
Capítulo 7 ■ SportSStore: una aplicación real
El documento HTML incluye una aplicación elemento, que es el marcador de posición para la funcionalidad SportsStore. También hay una base elemento,
que es requerido por las características de enrutamiento de URL angular, que agrego al proyecto SportsStore en el capítulo 8 .
Una parte importante de la creación de cualquier aplicación angular es crear la estructura de carpetas. los ng nueva
comando establece un proyecto que pone todos los archivos de la aplicación en el src carpeta, con los archivos angular en el
src / app carpeta. Para añadir un poco de estructura para el proyecto, crear las carpetas adicionales que se muestran en la Tabla 7-1 .
Carpeta Descripción
SportsStore / src / app / modelo Esta carpeta contiene el código para el modelo de datos.
SportsStore / src / app / tienda Esta carpeta contiene la funcionalidad básica para ir de compras.
SportsStore / src / app / admin Esta carpeta contiene la funcionalidad para la administración.
Este comando iniciará las herramientas de desarrollo establecidos por el ng nueva de comandos, lo que compilar y empaquetar los
archivos de código y contenidos en el automática src carpeta cada vez que se detecta un cambio. Una nueva ventana del navegador se abrirá y
mostrar el contenido se ilustra en la figura 7-1 .
El servidor web de desarrollo se inicia en el puerto 3000, por lo que la dirección URL de la aplicación será http: // localhost: 3000. Usted
no tiene que incluir el nombre del documento HTML, porque index.html es el archivo predeterminado que el servidor responde con.
112
Capítulo 7 ■ SportSStore: una aplicación real
El servicio web REST está configurado para ejecutarse en el puerto 3500. Para probar la solicitud de servicio web, utilizar el navegador para
solicitar la URL http: // localhost: 3500 / productos / 1. El navegador mostrará una representación JSON de uno de los productos definidos en el
Listado 7-3 , como sigue:
{
"Id": 1,
"Name": "Kayak",
"Categoría": "deportes acuáticos",
"Descripción": "Un barco para una persona", "precio":
275}
El componente de raíz es el bloque de construcción angular que gestionará el contenido de la aplicación elemento en el documento HTML de la lista 7-5 .
Una aplicación puede contener muchos componentes, pero siempre hay un componente de raíz que asume la responsabilidad por el contenido de primer
nivel se presenta al usuario. He editado el archivo llamado
app.component.ts en el SportsStore / src / app carpeta y se reemplaza el código existente con las declaraciones que aparecen en el listado 7-6 .
@Component ({selector:
"aplicación",
Plantilla: `<div class = "bg-éxito p-2-texto centro de texto blanco">
Esta es SportsStore </
div> `
})
AppComponent clase de exportación {}
Los @ Componente decorador dice que el angular AppComponent clase es un componente y sus propiedades configurar cómo se aplica el
componente. El conjunto completo de propiedades de los componentes descritos en el Capítulo 17 , Pero las propiedades que aparecen en la lista
son los más básicos y de uso más frecuente.
113
Capítulo 7 ■ SportSStore: una aplicación real
propiedad define el contenido HTML del componente mostrará. Los componentes pueden definir plantillas en línea, como éste, o utilizar archivos
HTML externos, que pueden hacer la gestión de contenidos complejos más fácil.
No hay ningún código en el AppComponent clase porque existe el componente de raíz en un proyecto angular sólo para administrar el contenido se muestra al
usuario. Al principio, me las arreglaré el contenido mostrado por el componente de raíz de forma manual, pero en el capítulo 8 , Utilizo una función llamada enrutamiento de
URL para adaptar el contenido automáticamente en función de las acciones del usuario.
El módulo de raíz se utiliza para describir la aplicación de angular. La descripción incluye los cuales se requieren módulos de función para
ejecutar la aplicación, que las características de encargo deben cargarse, y el nombre del componente de raíz. El nombre convencional del
archivo de componente raíz es app.module.ts, que se crea en el SportsStore / src / app carpeta. No se requieren cambios a este archivo por el
momento, y su contenido inicial se muestra en el Listado 7-7 .
@NgModule ({
declaraciones: [AppComponent], las
importaciones: [BrowserModule], los proveedores
de: [],
bootstrap: [AppComponent]})
Al igual que en el componente de raíz, no hay ningún código en la clase del módulo de raíz. Eso es porque el módulo de raíz en realidad sólo existe
para proporcionar la información a través de la @ NgModule decorador. los importaciones propiedad dice angular que debe cargar el BrowserModule módulo
de función, que contiene las características angulares básicas requeridas para una aplicación web.
los declaraciones propiedad dice angular que debe cargar el componente raíz, el proveedores
propiedad dice angular alrededor de los objetos compartidos utilizados por la aplicación y el oreja propiedad dice angular que el componente fundamental es
la AppModule clase. Voy a añadir información a las propiedades de este decorador como añado características para la aplicación SportsStore, pero esta
configuración básica es suficiente para iniciar la aplicación.
El 114 selector propiedad dice angular cómo aplicar el componente en el documento HTML, y el modelo
Capítulo 7 ■ SportSStore: una aplicación real
si (environment.production)
{enableProdMode (); }
Las herramientas de desarrollo detectan los cambios en el archivo del proyecto, compilar los archivos de código, y recargar automáticamente el navegador,
Cada modelo de datos debe clases que describen los tipos de datos que se contienen en el modelo de datos. Para la aplicación SportsStore, esto
significa que describen las clases de los productos que se venden en la tienda y las órdenes que se reciben de los clientes.
Ser capaz de describir los productos será suficiente para empezar a trabajar con la aplicación SportsStore, y voy a crear otras clases del modelo para
apoyar características como las ponen en práctica. He creado un archivo llamado product.model.ts
en el SportsStore / src / app / modelo carpeta y añade el código del listado 7-9 .
115
Capítulo 7 ■ SportSStore: una aplicación real
constructor(
Identificación del público ?: número, cadena
de nombre público ?:, categoría de público ?:
cadena, descripción público ?: cadena, precio
público ?: número) {}}
los Producto clase define un constructor que acepta Identificación, nombre, categoría, descripción, y precio
propiedades, que corresponden a la estructura de los datos utilizados para poblar el servicio web REST en el Listado 7-3 . Los signos de interrogación (?
Los caracteres) que siguen los nombres de los parámetros indican que estos son parámetros opcionales que pueden ser omitidos cuando se crean nuevos
objetos utilizando la Producto clase, que puede ser útil cuando se escriben las aplicaciones en las propiedades de modelo de objetos se rellenarán
utilizando formularios HTML.
He añadido un archivo llamado static.datasource.ts al SportsStore / src / app / modelo carpeta y se define la clase de muestra en el listado 7-10 .
@Injectable ()
StaticDataSource clase de exportación {
productos privados de producto: [] = [
nuevo producto (1, "Producto 1", "Categoría 1", "Producto 1 (Categoría 1)", 100), el nuevo producto (2, "Producto 2", "Categoría 1", "Producto 2
(Categoría 1)" , 100), el nuevo producto (3, "Producto 3", "Categoría 1", "Producto 3 (Categoría 1)", 100), el nuevo producto (4, "Producto 4",
"Categoría 1", "Producto 4 ( Categoría 1)", 100), el nuevo producto (5, "producto 5", "Categoría 1", "Producto 5 (categoría 1)", 100), el nuevo
producto (6, "Producto 6", "Categoría 2", "Producto 6 (categoría 2)", 100), el nuevo producto (7, "Producto 7", "Categoría 2", "Producto 7
(categoría 2)", 100), el nuevo producto (8, "Producto 8", " Categoría 2" , "Producto 8 (categoría 2)", 100), el nuevo producto (9 "Producto 9" ,
"Categoría 2", "Producto 9 (categoría 2)", 100), el nuevo producto (10, "producto 10", "Categoría 2", "producto 10 (categoría 2)", 100), los
productos nuevos (11 "11 de producto", "Categoría 3", "Producto 11 (Categoría 3)", 100), el nuevo producto (12, "Producto 12", "categoría 3",
"Producto 12 (Categoría 3)", 100 ), los productos nuevos (13, "Producto 13", "categoría 3", "Producto 13 (Categoría 3)", 100), el nuevo producto
(14, "Producto 14", "categoría 3", "Producto 14 (Categoría 3 )", 100), el nuevo producto (15, "Producto 15", "Categoría 3", "Producto 15
(Categoría 3)", 100),];Categoría 2" , "Producto 10 (categoría 2)", 100), el nuevo producto (11, "Producto 11", "Categoría 3", "Producto 11
(Categoría 3)", 100), el nuevo producto (12, "Producto 12" , "categoría 3", "Producto 12 (Categoría 3)", 100), el nuevo producto (13, "Producto
13", "categoría 3", "Producto 13 (Categoría 3)", 100), el nuevo producto ( 14, "14 Producto", "categoría 3", "Producto 14 (Categoría 3)", 100), el
nuevo producto (15, "Producto 15", "categoría 3", "Producto 15 (Categoría 3)", 100) ,];Categoría 2" , "Producto 10 (categoría 2)", 100), el nuevo
producto (11, "Producto 11", "Categoría 3", "Producto 11 (Categoría 3)", 100), el nuevo producto (12, "Producto 12" , "categoría 3", "Producto
12 (Categoría 3)", 100), el nuevo producto (13, "Producto 13", "categoría 3", "Producto 13 (Categoría 3)", 100), el nuevo producto ( 14, "14
Producto", "categoría 3", "Producto 14 (Categoría 3)", 100), el nuevo producto (15, "Producto 15", "categoría 3", "Producto 15 (Categoría 3)", 100) ,];100), el nuevo producto (13, "Pro
116
Capítulo 7 ■ SportSStore: una aplicación real
los StaticDataSource clase define un método llamado getProducts, que devuelve los datos ficticios. El resultado de llamar al getProducts
método es una Observable <Producto []>, que es una Observable que produce matrices de Producto objetos.
los Observable clase es proporcionada por el paquete de extensiones reactivas, que es utilizado por angular para manejar los cambios de estado
en las aplicaciones. Describo el Observable clase en el capítulo 23 , Pero para este capítulo, es suficiente para saber que una Observable objeto
representa una tarea asíncrona que producirá un resultado en algún momento en el futuro. Angular expone el uso de Observable Objetos para algunas
funciones, como hacer peticiones HTTP, y esta es la razón por la getProducts método devuelve una Observable <Producto []> en lugar de simplemente
devolver los datos de forma sincrónica.
Los @ inyectable decorador ha sido aplicada a la StaticDataSource clase. Este decorador se utiliza contar angular que esta clase será utilizada
como un servicio, que permite a otras clases para acceder a su funcionalidad a través de una característica llamada inyección de dependencia, que se
describe en los capítulos 19 y 20 . Vas a ver cómo funcionan los servicios como la aplicación toma forma.
■ Propina cuenta de que tengo que importar inyectable desde el @ angular / núcleo módulo de JavaScript para que pueda aplicar el @ inyectable decorador.
No voy a poner de relieve las diferentes clases de todos los angulares que i de importación para el ejemplo SportsStore, pero se puede obtener
todos los detalles en los capítulos que describen las características que se relacionan con.
@Injectable ()
ProductRepository clase de exportación {
productos privados: Producto [] = []; privadas
categorías: string [] = [];
117
Capítulo 7 ■ SportSStore: una aplicación real
Cuando angular tiene que crear una nueva instancia del repositorio, se inspeccionará la clase y ver que se necesita una StaticDataSource
oponerse a invocar la ProductRepository constructor y crear un nuevo objeto.
El constructor repositorio llama a la fuente de datos de getProducts método y luego utiliza el suscribir
método en el Observable objeto que se devuelve para recibir los datos de productos. Véase el capítulo 23 para más detalles de cómo Observable objetos de
trabajo.
■ Propina No se preocupe si todos los nombres de los archivos parecen similares y confuso. Se acostumbrará a la forma en que las aplicaciones
angulares están estructurados a medida que trabaja a través de los otros capítulos en el libro, y que pronto será capaz de mirar a los archivos en un
@NgModule ({
proveedores: [ProductRepository, StaticDataSource]})
Los @ NgModule decorador se utiliza para crear módulos de características, y sus propiedades diga angular de cómo se debe utilizar el módulo.
Sólo hay una propiedad en este módulo, proveedores, y se dice angular que las clases deben ser utilizados como servicios para la función de
inyección de dependencias, que se describe en los capítulos 19
y 20 . Características módulos-y el @ NgModule decorador-se describen en el Capítulo 21 .
118
Capítulo 7 ■ SportSStore: una aplicación real
Inicio de la tienda
Ahora que el modelo de datos está en su lugar, puedo empezar a construir la funcionalidad de la tienda, que le permitirá al usuario ver los productos para la
venta y hacer pedidos para ellos. La estructura básica de la tienda será un diseño de dos columnas, con botones de categoría que permiten que la lista de
productos que se va a filtrar y una tabla que contiene la lista de productos, como se ilustra en la figura 7-3 .
En las secciones que siguen, voy a usar rasgos angulosos y los datos en el modelo para crear el diseño mostrado en la figura.
Con esto en mente, el punto de partida para la funcionalidad de tienda será un componente nuevo, que es una clase que proporciona datos y la
lógica de una plantilla HTML, que contiene enlaces de datos que generan contenidos de forma dinámica. He creado un archivo llamado store.component.ts
en el SportsStore / src / app / tienda carpeta y se define la clase de muestra en el listado 7-13 .
@Componente({
Selector: "tienda",
templateUrl: "store.component.html"})
119
Capítulo 7 ■ SportSStore: una aplicación real
Los @ Componente decorador ha sido aplicada a la StoreComponent clase, que dice angular que es un componente. Las propiedades del
decorador dicen angular cómo aplicar el componente de contenido HTML (usando un elemento llamado almacenar) y cómo encontrar la plantilla del
componente (en un archivo llamado store.component.html).
los StoreComponent clase proporciona la lógica que apoyará el contenido de la plantilla. El constructor recibe una ProductRepository objeto
como un argumento, proporcionada a través de la función de inyección de dependencia se describe en los capítulos 20 y 21 . Los componentes
define productos y categorías propiedades que se van a utilizar para generar contenido HTML en la plantilla, utilizando los datos obtenidos desde el
repositorio. Para proporcionar el componente con su plantilla, he creado un archivo llamado store.component.html en el SportsStore / src / app /
tienda carpeta y añade el contenido HTML se muestra en el Listado 7-14 .
Listado 7-14. Los contenidos del archivo store.component.html en la carpeta src / app / tienda
La plantilla es simple, sólo para empezar. La mayor parte de los elementos proporcionan la estructura para la distribución de la tienda y se
aplican algunas clases CSS Bootstrap. Sólo hay dos enlaces de datos en el momento angular, que están indicados por las {{y}} caracteres. Estos son interpolación
de cadenas encuadernaciones, y ellos dicen angular para evaluar la expresión de enlace e introduzca el resultado en el elemento. Las expresiones en
estos enlaces muestran el número de productos y categorías previstas por el componente de almacén.
120
Capítulo 7 ■ SportSStore: una aplicación real
@NgModule ({
importaciones: [ModelModule, BrowserModule, FormsModule], declaraciones:
[StoreComponent], las exportaciones: [StoreComponent]})
Los @ NgModule decorador configura el módulo, utilizando el importaciones propiedad para decirle angular que el módulo de tienda depende del
módulo de modelo, así como BrowserModule y FormsModule, que contienen las características angulares estándar para aplicaciones web y trabajar con
elementos de formulario HTML. El decorador utiliza el declaraciones propiedad para decirle angular alrededor del StoreComponent clase, que la exportaciones
propiedad dice angular puede ser utilizado también en otras partes de la aplicación, lo cual es importante porque va a ser utilizado por el módulo de
raíz.
@Componente({
Selector: "aplicación",
plantilla: "<store> </ tienda>"
})
AppComponent clase de exportación {}
los almacenar elemento reemplaza el contenido anterior de la plantilla del componente de la raíz y se corresponde con el valor de la selector propiedad
de la @ Componente decorador en el Listado 7-13 . Listado 7-17 muestra el cambio necesario para el módulo de raíz para que Angular carga el
módulo característica que contiene la funcionalidad de tienda.
Listado 7-17. Importación de módulos de características en los app.module.ts archivo en la carpeta src / app
@NgModule ({
121
Capítulo 7 ■ SportSStore: una aplicación real
Al guardar los cambios en el módulo de raíz, angular tendrá todos los detalles que necesita para cargar la aplicación y mostrar el
contenido del módulo de tienda, como se muestra en la figura 7-4 . Todos los bloques de construcción creado en la sección anterior
trabajan juntos para mostrar la verdad es simple: el contenido, lo que demuestra la cantidad de productos que hay y cuántas categorías
encajan a.
Listado 7-18. La adición de elementos en el archivo store.component.html en la carpeta src / app / tienda
122
Capítulo 7 ■ SportSStore: una aplicación real
<Div class = "tarjeta de texto bg-blanca p-1"> {{}} PRODUCT.DESCRIPTION </ div> </ div> </ div>
</ Div>
La mayor parte de los elementos de control del diseño y el aspecto del contenido. El cambio más importante es la adición de una expresión
de enlace de datos angulares.
. . . <Div * ngFor = "dejar que el producto de los productos" class = "tarjeta de m-1 P-1 bg-luz">
...
Este es un ejemplo de una directiva, que transforma el elemento HTML que se aplica. Esta directiva específica se llama ngFor, y
transforma la div elemento mediante la duplicación de que para cada objeto devuelto por el componente de productos propiedad. Angular
incluye una serie de directivas incorporadas que realizan las tareas más comúnmente requerida, tal como se describe en el capítulo 13 . Ya que
duplica la div elemento, el objeto actual se asigna a una variable llamada producto, que permite que se hace referencia en otros enlaces de
datos, tales como éste, que inserta el valor del producto actual de nombre Descripción del inmueble como el contenido de la div elemento:
...
<Div class = "tarjeta de texto p-1 BG-blanco"> {{ PRODUCT.DESCRIPTION}} </ div>
...
No todos los datos en el modelo de datos de una aplicación se pueden visualizar directamente al usuario. Angular incluye una característica llamada tubería,
que son clases que se utilizan para transformar o preparar un valor de datos para su uso en un enlace de datos. Hay varias tuberías integradas incluidas con
angular, incluyendo el moneda pipa, que da formato a valores numéricos como monedas, así:
...
{{Product.price | la divisa: "USD": "símbolo": "2.2-2"}}
...
La sintaxis para la aplicación de las tuberías puede ser un poco incómodo, pero la expresión en esta unión dice angular para formatear la precio
propiedad del producto actual con el moneda tubería, con las convenciones de moneda de los Estados Unidos. Guarde los cambios en la plantilla, y
verá una lista de los productos en el modelo de datos se muestra como una larga lista, como se ilustra en la figura 7-5 .
123
Capítulo 7 ■ SportSStore: una aplicación real
Añadir soporte para el filtrado de la lista de productos por categoría requiere la preparación del componente de almacén de modo que mantiene un registro de qué
categoría el usuario quiere visualizar y requiere cambiar la forma en que los datos se recuperan de usar esa categoría, como se muestra en el Listado 7-19 .
Listado 7-19. Añadiendo una Categoría de filtrado en los store.component.ts archivo en la carpeta src / app / tienda
@Componente({
Selector: "tienda",
templateUrl: "store.component.html"})
124
Capítulo 7 ■ SportSStore: una aplicación real
this.selectedCategory = newCategory; }
Los cambios son simples, ya que construir sobre la base de que tomó tanto tiempo para crear al comienzo del capítulo. los selectedCategory
la propiedad se le asigna la elección del usuario de categoría (donde nulo significa todas las categorías) y se utiliza en el actualizar datos método
como un argumento a la getProducts método, delegar el filtrado a la fuente de datos. los changeCategory método trae estos dos miembros juntos
en un método que puede ser invocado cuando el usuario realiza una selección de categoría.
Listado 7-20 muestra los cambios correspondientes en la plantilla del componente para proporcionar al usuario con el conjunto de botones que
cambian la categoría seleccionada y mostrar que ha sido recogido categoría.
Listado 7-20. Añadiendo Categoría Botones en el Archivo store.component.html en la carpeta src / app / tienda
<Div class = "tarjeta de texto bg-blanca p-1"> {{}} PRODUCT.DESCRIPTION </ div> </ div> </ div> </
div> </ div>
Hay dos nuevos botón elementos en la plantilla. La primera es una Casa botón, y se ha de unión a un evento que invoca el componente de changeCateg
método cuando se hace clic en el botón. Ningún argumento se proporciona al método, que tiene el efecto de establecer la categoría a la nulo y la
selección de todos los productos.
los ngFor La unión se ha aplicado a la otra botón elemento, con una expresión que se repetirá el elemento para cada valor en la matriz
devuelta por el componente de categorías propiedad. los botón tiene un hacer clic de enlaces de sucesos cuya expresión llama al changeCategory
Método para seleccionar la categoría actual,
125
Capítulo 7 ■ SportSStore: una aplicación real
que filtrará los productos que se muestran al usuario. También hay una clase vinculante, que añade el elemento de botón a la activo clase
cuando la categoría asociada con el botón es la categoría seleccionada. Esto proporciona al usuario con información visual cuando se filtran
las categorías, como se muestra en la figura 7-6 .
Filtrado de los productos por categorías ha ayudado a hacer la lista de productos más manejables, pero un enfoque más típica es la de romper la lista en
secciones más pequeñas y presentar cada uno de ellos como una página, junto con los botones de navegación que se mueven entre las páginas. Listado 7-21
Aumenta el componente tienda para que no pierde de vista la página actual y el número de elementos de una página.
Listado 7-21. La adición de paginación apoyo en la store.component.ts archivo en la carpeta src / app / tienda
@Componente({
Selector: "tienda",
templateUrl: "store.component.html"})
126
Capítulo 7 ■ SportSStore: una aplicación real
Hay dos nuevas características en este listado. El primero es la capacidad de conseguir una página de productos, y el segundo es para cambiar el tamaño de
las páginas, permitiendo que el número de productos que contiene cada página a ser alterado.
No es una rareza que el componente tiene que evitar. Hay una limitación en el built-in ngFor
directiva que Angular ofrece, que puede generar contenido sólo para los objetos en una matriz o una colección, en lugar de utilizar un contador. Desde que
necesita para generar botones de navegación de páginas numeradas, esto significa que necesito para crear una matriz que contiene los números que
necesito, así:
...
volver Array (Math.ceil (this.repository.getProducts (this.selectedCategory) .length
/ This.productsPerPage)). llenar( 0). mapa(( x, i) => i + 1);
...
Esta sentencia crea una nueva matriz, lo llena con el valor 0, y luego utiliza la mapa método para generar una nueva matriz con la secuencia de
números. Esto funciona bastante bien como para implementar la función de paginación, pero se siente incómodo, y que demuestran un mejor enfoque en
la siguiente sección. Listado 7-22 muestra los cambios en la plantilla del componente de almacén para implementar la función de paginación.
Listado 7-22. La adición de la paginación en el Archivo de store.component.html en la carpeta src / app / tienda
127
Capítulo 7 ■ SportSStore: una aplicación real
Inicio </
botón>
<Botón * ngFor = "dejar que el gato de las categorías"
class = "btn btn-outline-primaria BTN-bloque"
[Class.active] = "gato == selectedCategory" (click) = "changeCategory (cat)"> {{cat}} </ button> </
div>
<Div class = "tarjeta de texto bg-blanca p-1"> {{}} PRODUCT.DESCRIPTION </ div> </ div>
Los nuevos elementos añaden una seleccionar elemento que permite que el tamaño de la página para cambiar y un conjunto de botones que navegan a través de
las páginas de productos. Los nuevos elementos tienen enlaces de datos para cablear hacia arriba a las propiedades y métodos proporcionados por el componente. El
128
Capítulo 7 ■ SportSStore: una aplicación real
■ Propina la seleccionar elemento de la lista 7-22 se rellena con opción elementos que están definidas estáticamente, en lugar de crear utilizando los
datos desde el componente. Una de las consecuencias de esto es que cuando el valor seleccionado se pasa a la changePageSize método, que será
número antes de ser utilizados para establecer el tamaño de página en la lista 7-21 . Se debe tener cuidado cuando se recibe valores de datos de los
elementos HTML para asegurar que son del tipo esperado. Tipo mecanografiado anotaciones no ayudan en esta situación porque la expresión de enlace
de datos se evalúa en tiempo de ejecución, mucho después de que el compilador mecanografiado ha generado el código JavaScript que no contiene la
129
Capítulo 7 ■ SportSStore: una aplicación real
En esta sección, voy a crear una directiva personalizada para que yo no tengo que generar una amplia gama de números para crear los botones de
navegación. Angular ofrece una buena gama de directivas incorporadas, pero es un proceso simple para crear sus propias directivas para resolver
problemas que son específicos de su aplicación o para apoyar características que las directivas incorporadas no tienen. He añadido un archivo llamado counter.directive.ts
en el
src / app / tienda carpeta y lo utilizó para definir la clase de muestra en el listado 7-23 .
{importación
@Directiva({
Selector: "[counterOf]"})
@Input ( "counterOf")
contador: número;
CounterDirectiveContext clase {
constructor ($ pública implícita: los hay) {}}
Este es un ejemplo de una directiva estructural, que se describe en detalle en el capítulo dieciséis . esta directiva
se aplica a los elementos a través de una mostrador propiedad y se basa en las características especiales que ofrece angular para la creación de contenido en varias
ocasiones, al igual que el built-in ngFor directiva. En este caso, en lugar de producir cada objeto en una colección, la directiva personalizada produce una serie de
números que se pueden utilizar para crear los botones de navegación.
■ Propina esta directiva elimina todo el contenido que ha creado y comienza de nuevo cuando el número de páginas cambios. esto puede ser
un proceso costoso en las directivas más complejas, y explicar cómo mejorar el rendimiento en el capítulo dieciséis .
130
Capítulo 7 ■ SportSStore: una aplicación real
Para usar la directiva, debe ser añadido a la declaraciones propiedad de su módulo de función, como se muestra en el Listado 7-24 .
Listado 7-24. Registro de la Directiva personalizado en el store.module.ts archivo en la carpeta src / app / tienda
@NgModule ({
importaciones: [ModelModule, BrowserModule, FormsModule],
declaraciones: [StoreComponent, CounterDirective],
exportaciones: [StoreComponent]})
Ahora que la directiva ha sido registrado, se puede utilizar en la plantilla del componente de almacén para reemplazar el ngFor Directiva, como se
muestra en el Listado 7-25 .
Listado 7-25. Sustitución de la Directiva incorporado en el archivo store.component.html en la carpeta src / app / tienda
<Div class = "tarjeta de texto bg-blanca p-1"> {{}} PRODUCT.DESCRIPTION </ div>
131
Capítulo 7 ■ SportSStore: una aplicación real
</ Div>
Los nuevos datos de unión se basa en una propiedad llamada pageCount para configurar la directiva personalizada. en el Listado 7-26 , He sustituido
la matriz de números con un simple número que proporciona el valor de expresión.
Listado 7-26. El apoyo a la Directiva personalizado en el store.component.ts archivo en la carpeta src / app / tienda
@Componente({
Selector: "tienda",
templateUrl: "store.component.html"})
132
Capítulo 7 ■ SportSStore: una aplicación real
No hay ningún cambio visual para la aplicación SportsStore, pero esta sección ha demostrado esto, es posible complementar la funcionalidad
angular integrado con un código personalizado que se adapte a las necesidades de un proyecto específico.
Resumen
En este capítulo, empecé el proyecto SportsStore. La primera parte del capítulo se gastó la creación de las bases para el proyecto, incluyendo la creación de los
bloques de construcción de la raíz de la aplicación y empezar a trabajar en los módulos de características. Una vez que la base estaba en su lugar, yo era capaz de
añadir rápidamente características para mostrar los datos del modelo de maniquí para el usuario, agregar la paginación, y filtrar los productos por categoría. Terminé
el capítulo mediante la creación de una directiva personalizada para demostrar cómo las características incorporadas proporcionadas por angular pueden
complementarse con código personalizado. En el siguiente capítulo, continúo para construir la aplicación SportsStore.
133
CAPÍTULO 8
En este capítulo, continúo la adición de características a la aplicación SportsStore que he creado en el Capítulo 7 . Agrego soporte para un carro
de compras y un proceso de pago y vuelva a colocar los datos ficticios con los datos del servicio web REST.
Abrir una segunda línea de comandos y ejecute el comando siguiente en el Tienda de deportes carpeta para iniciar las herramientas de desarrollo
y servidor HTTP:
■ Propina Puede descargar el proyecto de ejemplo para este capítulo, y para todos los demás capítulos de este libro: de https://github.com/Apress/pro
.
Creación de la Cesta
El usuario necesita un carro en el que los productos pueden ser colocados y utilizados para iniciar el proceso de pago. En las secciones que siguen, voy a añadir
un carrito de la aplicación e integrarla en la tienda de manera que el usuario puede seleccionar los productos que desean.
@Injectable ()
clase de exportación de la compra {
this.recalculate (); }
this.recalculate (); }
claro() {
this.lines = [];
this.itemCount = 0;
this.cartPrice = 0; }
this.itemCount + = l.quantity;
this.cartPrice + = (l.quantity * l.product.price); })}}
136
Capítulo 8 ■ Spor tSStore: órdenes y salida
obtener LineTotal () {
volver this.quantity * this.product.price; }}
selecciones de productos individuales se representan como un conjunto de CartLine objetos, cada uno de los cuales contiene una Producto objeto
y una cantidad. los Carro clase no pierde de vista el número total de elementos que se han seleccionado y su coste total.
Debe haber una sola Carro objeto que se utiliza en toda la aplicación, lo que garantiza que cualquier parte de la aplicación puede acceder
a la selección de productos del usuario. Para lograr esto, voy a hacer el Carro un servicio, lo que significa que angular tendrá la responsabilidad
de crear una instancia de la Carro clase y lo utilizará cuando se necesita para crear un componente que tiene una Carro argumento del
constructor. Este es otro uso de la función de inyección de dependencia angular, que puede ser utilizado para compartir objetos a lo largo de
una aplicación y que se describe en detalle en los capítulos 19 y 20 . Los @ inyectable decorador, que ha sido aplicado a la Carro clase en el perfil,
indica que esta clase será utilizada como un servicio.
■ Nota Estrictamente hablando, el @ inyectable Se requiere decorador sólo cuando una clase tiene sus propios argumentos de constructor para resolver,
pero es una buena idea para aplicar de todos modos, ya que sirve como una señal de que la clase es para uso como un servicio.
Listado 8-2 registra el Carro clase como un servicio en el proveedores propiedad de la clase módulo de función del modelo.
Listado 8-2. El registro del carro, como un servicio en el archivo model.module.ts en la carpeta src / app / modelo
@NgModule ({
proveedores: [ProductRepository, StaticDataSource, Cesta]
})
ModelModule clase de exportación {}
Los componentes son los elementos esenciales para aplicaciones angular, ya que permiten unidades discretas de código y contenido a crearse
fácilmente. La aplicación SportsStore mostrará a los usuarios un resumen de sus selecciones de productos en el área de título de la página, lo que
voy a poner en práctica mediante la creación de un componente. He añadido un archivo llamado cartSummary.component.ts en el src / app / tienda carpeta
y lo utilizó para definir el componente de muestra en el listado 8-3 .
137
Capítulo 8 ■ Spor tSStore: órdenes y salida
@Componente({
Selector: "cesta-Resumen",
templateUrl: "cartSummary.component.html"})
Cuando angular necesita para crear una instancia de este componente, se tendrá que proporcionar una Carro objeto como un argumento del constructor,
utilizando el servicio que he configurado en la sección anterior, añadiendo el Carro la clase a la década de los módulos de funciones proveedores propiedad. El
comportamiento por defecto para los servicios significa que una sola Carro
objeto se crea y se comparte en toda la aplicación, aunque hay diferentes comportamientos de servicios disponibles (como se describe en el
capítulo 20 ).
Para proporcionar el componente con una plantilla, he creado un archivo HTML llamado cartSummary.component.html
en la misma carpeta que el archivo de clase de componente añadido y el marcado se muestra en el Listado 8-4 .
Listado 8-4. Los contenidos del cartSummary.component.html archivo en la carpeta src / app / tienda
Esta plantilla utiliza la Carro objeto proporcionado por su componente para visualizar el número de artículos en el carro y el costo total. También
hay un botón que se iniciará el proceso de pago cuando lo añado a la aplicación más adelante en el capítulo.
■ Propina el elemento de botón en el Listado 8-4 se labró el uso de clases definidas por Font impresionante, que es uno de los paquetes en el package.json
presentar en el capítulo 7 . este paquete de código abierto ofrece un excelente soporte para iconos de aplicaciones web, incluyendo el carrito de la
compra que necesito para la aplicación SportsStore. Ver http: // fontawesome.io para detalles.
138
Capítulo 8 ■ Spor tSStore: órdenes y salida
Listado 8-5 registra el nuevo componente con el módulo de función tienda, en preparación para su uso en la siguiente sección.
Listado 8-5. Registrar el componente en el archivo store.module.ts en la carpeta src / app / tienda
@NgModule ({
importaciones: [ModelModule, BrowserModule, FormsModule],
declaraciones: [StoreComponent, CounterDirective, CartSummaryComponent],
exportaciones: [StoreComponent]})
Listado 8-6. La adición de la compra Atención en el Archivo store.component.ts en la carpeta src / app / tienda
@Componente({
Selector: "tienda",
templateUrl: "store.component.html"})
139
Capítulo 8 ■ Spor tSStore: órdenes y salida
Para completar la integración del carro en el componente de almacén, el Listado 8-7 agrega el elemento que se aplicará el componente
resumen del carrito de la plantilla del componente de almacén y añade un botón para cada descripción del producto con la unión que llama al
evento addProductToCart método.
Listado 8-7. La aplicación del componente en el archivo store.component.html en la carpeta src / app / tienda
140
Capítulo 8 ■ Spor tSStore: órdenes y salida
El resultado es un botón para cada producto que lo añade al carro, como se muestra en la figura 8-1 . El carro lleno
proceso no está completo, pero se puede ver el efecto de cada adición en el resumen de la cesta en la parte superior de la página.
141
Capítulo 8 ■ Spor tSStore: órdenes y salida
Observe cómo hacer clic en uno de los botones Añadir al carro actualiza el contenido del componente Resumen de forma automática. Esto
sucede porque hay una sola Carro objeto que se comparte entre dos componentes y los cambios realizados por uno de los componentes se reflejan
cuando Angular evalúa las expresiones de unión en el otro componente de datos.
Para la aplicación SportsStore, voy a añadir soporte para tres direcciones URL diferentes, que se describen en la tabla 8-1 . Esta es una configuración
simple, pero el sistema de encaminamiento tiene un montón de características, que se describen en detalle en los capítulos 25 a 27 .
URL Descripción
142
Capítulo 8 ■ Spor tSStore: órdenes y salida
En las secciones que siguen, se crea componentes de marcador de posición para las etapas carrito SportsStore y salida orden y luego integrarlos en
la aplicación mediante el enrutamiento de URL. Una vez que se implementan las direcciones URL, voy a volver a los componentes y añadir más funciones
útiles.
@Componente({
Plantilla: `<div> <h3 class = "bg-p-1 información de texto blanco"> carro Detallada de componentes </ h3> </ div>`})
A continuación, he añadido un archivo llamado checkout.component.ts en el src / app / tienda carpeta y se define el componente de muestra en el
listado 8-9 .
@Componente({
Plantilla: `<div> <h3 class = "bg-p-1 información de texto blanco"> Pedido de componentes </ h3> </ div>`})
Este componente sigue el mismo patrón que el componente de la cesta y muestra un mensaje de marcador de posición. Listado 8-10 registra los
componentes en el módulo de función tienda y los añade a la exportaciones propiedad, lo que significa que se pueden utilizar en otras partes de la
aplicación.
Listado 8-10. Registro de componentes en el store.module.ts archivo en la carpeta src / app / tienda
@NgModule ({
importaciones: [ModelModule, BrowserModule, FormsModule],
declaraciones: [StoreComponent, CounterDirective, CartSummaryComponent,
CartDetailComponent, CheckoutComponent],
143
Capítulo 8 ■ Spor tSStore: órdenes y salida
las direcciones URL en componentes. Cada asignación de un URL a un componente que se conoce como una
ruta URL o sólo una ruta. En la parte 3, donde puedo crear configuraciones de enrutamiento más complejas, defino las rutas en un archivo separado, pero
para este proyecto, voy a seguir un enfoque más sencillo y definir las rutas dentro de la
@NgModule decorador del módulo raíz de la aplicación, como se muestra en el Listado 8-11 .
■ Propina la función de enrutamiento angular requiere una base elemento en el documento HTML, que proporciona la URL de base contra la cual se
aplican las rutas. este elemento se añadió a la index.html presentar por el ng nueva comando cuando creé el proyecto SportsStore en el capítulo 7 . Si se
omite el elemento angular informará de un error y ser incapaces de aplicar las rutas.
Listado 8-11. Creación de la configuración de enrutamiento en los app.module.ts archivo en la carpeta src / app
@NgModule ({
importaciones: [BrowserModule, StoreModule,
RouterModule.forRoot ([
{Ruta: "tienda", componente: StoreComponent}, {ruta: "carrito",
componente: CartDetailComponent}, {ruta: "checkout",
componente: CheckoutComponent}, {ruta: "**", RedirectTo: "/
tienda" }])],
declaraciones: [AppComponent],
bootstrap: [AppComponent]})
los RouterModule.forRoot método se aprobó un conjunto de rutas, cada una de las cuales se asigna una dirección URL a un componente. Las tres
primeras rutas en el listado coinciden con las direcciones URL de la tabla 8-1 . La ruta final es un comodín que redirige cualquier otra URL a / almacenar, que
mostrará StoreComponent.
Cuando se utiliza la función de enrutamiento, angular busca la enrutador de salida elemento, que define la ubicación en la que
el componente que corresponde a la URL actual se debe mostrar. Listado 8-12
sustituye a la almacenar elemento de la plantilla de la raíz con el componente enrutador de salida elemento.
144
Capítulo 8 ■ Spor tSStore: órdenes y salida
Listado 8-12. Definir el enrutamiento de destino en los app.component.ts archivo en la carpeta src / app
@Componente({
Selector: "aplicación",
plantilla: "<enrutador de salida> </ enrutador de salida>"
})
AppComponent clase de exportación {}
Angular se aplicará la configuración de enrutamiento al guardar los cambios y el navegador vuelve a cargar el documento HTML. El contenido que
se muestra en la ventana del navegador no ha cambiado, pero si se examina la barra de direcciones del navegador, usted será capaz de ver que la
configuración de enrutamiento se ha aplicado, como se muestra en la figura 8-2 .
Cuando el usuario hace clic en uno de los botones Añadir al carro, el componente de la cesta detalle debe ser mostrado, lo que significa que la
aplicación debe navegar a la / carro URL. Listado 8-13 añade navegación para el método de componentes que se invoca cuando el usuario hace clic en el
botón.
Listado 8-13. Navegando Uso de JavaScript en el archivo store.component.ts en la aplicación / src / carpeta de almacén
145
Capítulo 8 ■ Spor tSStore: órdenes y salida
@Componente({
Selector: "tienda",
templateUrl: "store.component.html"})
El constructor tiene una Router parámetro, que es proporcionada por angular a través de la función de inyección de dependencia cuando
se crea una nueva instancia del componente. En el addProductToCart método, el
Router.navigateByUrl método se utiliza para navegar a la / carro URL.
146
Capítulo 8 ■ Spor tSStore: órdenes y salida
La navegación también se puede hacer mediante la adición de la routerLink atribuir a los elementos de la plantilla. en el Listado 8-14 , la
routerLink atributo se ha aplicado al botón del carro en la plantilla de la compra de componentes de resumen.
Listado 8-14. Adición de una navegación en el archivo cartSummary.component.html en la carpeta src / app / tienda
El valor especificado por la routerLink atributo es la dirección URL que la aplicación se vaya a cuando el
botón se hace clic. Este botón concreto se desactiva cuando el carro está vacío, por lo que llevará a cabo la navegación sólo cuando el usuario ha
añadido un producto a la cesta.
Para añadir soporte para el routerLink atributo, el RouterModule módulo debe ser importada en el módulo de función, como se muestra
en el Listado 8-15 .
Listado 8-15. Importación del módulo de router en la store.module.ts archivo en la carpeta src / app / tienda
@NgModule ({
importaciones: [ModelModule, BrowserModule, FormsModule, RouterModule],
declaraciones: [StoreComponent, CounterDirective, CartSummaryComponent,
CartDetailComponent, CheckoutComponent],
exportaciones: [StoreComponent, CartDetailComponent, CheckoutComponent]})
Para ver el efecto de la navegación, guardar los cambios de los archivos y, una vez que el navegador ha vuelto a cargar el documento HTML, haga
clic en uno de los botones Añadir al carro. El navegador se vaya a la / carro URL, como se muestra en la figura 8-3 .
147
Capítulo 8 ■ Spor tSStore: órdenes y salida
A modo de ejemplo, si hace clic en uno de los botones Añadir al carro y haga clic en el botón de recarga del navegador, el servidor HTTP
devolverá el contenido de la index.html archivo y angular saltará inmediatamente al componente de la cesta detalle, pasando por alto la parte de la
aplicación que permite al usuario seleccionar productos.
Para algunas aplicaciones, pudiendo comenzar a utilizar diferentes direcciones URL tiene sentido, pero si ese no es el caso, entonces soportes angulares guardias
148
Capítulo 8 ■ Spor tSStore: órdenes y salida
@Injectable ()
StoreFirstGuard clase de exportación {
firstNavigation privada = true;
return true; }}
Hay diferentes maneras de protegerse rutas, tal como se describe en el capítulo 27 , Y esto es un ejemplo de un guardia
que impide una ruta de ser activado, que se implementa como una clase que define una canActivate
método. La implementación de este método utiliza los objetos de contexto que Angular proporciona que describen la ruta que está a punto de ser
navegado a y se comprueba para ver si el componente diana es una StoreComponent.
Si esta es la primera vez que el canActivate método ha sido llamado y un componente diferente está a punto de ser utilizado, a continuación, la Router.navigateByU
método se utiliza para navegar a la URL raíz.
Los @ inyectable decorador se ha aplicado en la lista porque los guardias de ruta son los servicios. Listado 8-17
registra la guardia como un servicio a través de los módulos de la raíz proveedores propiedad y guarda cada ruta mediante el
canActivate propiedad.
Listado 8-17. Que guardan en las rutas app.module.ts archivo en la carpeta src / app
@NgModule ({
importaciones: [BrowserModule, StoreModule,
RouterModule.forRoot ([
{
ruta: "tienda", componente: StoreComponent,
canActivate: [StoreFirstGuard]
}, {
149
Capítulo 8 ■ Spor tSStore: órdenes y salida
{
ruta: "caja", componente: CheckoutComponent,
canActivate: [StoreFirstGuard]
},
{Ruta: "**", RedirectTo: "/ tienda"}])],
proveedores: [StoreFirstGuard],
declaraciones: [AppComponent],
bootstrap: [AppComponent]})
Si vuelve a cargar el navegador después de hacer clic en uno de los botones Añadir al carro ahora, entonces verá el navegador se dirige
automáticamente a la seguridad, como se muestra en la figura 8-4 .
Listado 8-18. Cambio de la plantilla en el archivo cartDetail.component.ts en la carpeta src / app / tienda
@Componente({
150
Capítulo 8 ■ Spor tSStore: órdenes y salida
templateUrl: "cartDetail.component.html"
})
CartDetailComponent clase de exportación {
Para completar la función de la cesta detalle, he creado un archivo HTML llamado cartDetail.component.html en el
src / app / tienda carpeta y añade el contenido se muestra en el Listado 8-19 .
Listado 8-19. Los contenidos del cartDetail.component.html archivo en la carpeta src / app / tienda
151
Capítulo 8 ■ Spor tSStore: órdenes y salida
<Td colspan = clase "3" = "text-derecha"> Total: </ td> <td class =
"text-derecha">
{{Cart.cartPrice | la divisa: "USD": "símbolo": "2.2-2"}} </ td> </ tr> </
tfoot> </ table> </ div> </ div>
Esta plantilla muestra una tabla que muestra la selección de productos del usuario. Para cada producto, hay una entrada
elemento que se puede utilizar para cambiar el botón Quitar una que lo elimina de la compra cantidad y. También hay dos botones de navegación
que permiten al usuario volver a la lista de productos o continuar con el proceso de compra, como se muestra en la figura 8-5 . La combinación de
los enlaces de datos angular y la compartida Carro objeto significa que cualquier cambio realizado en el carro tienen efecto inmediato, volver a
calcular los precios; y si hace clic en el botón Continuar compra, los cambios se reflejan en el componente resumen del carrito mostrado en la lista
de productos.
152
Capítulo 8 ■ Spor tSStore: órdenes y salida
Proceso de pedidos
Ser capaz de recibir órdenes de clientes es el aspecto más importante de una tienda en línea. En las secciones que siguen, no edificar sobre la
aplicación para añadir soporte para recibir los últimos detalles del usuario y la comprobación hacia fuera. Para mantener el proceso simple, voy a
evitar el trato con plataformas de pago y cumplimiento, que son generalmente los servicios de back-end que no son específicos de aplicaciones
angular.
Extender el modelo
Describir las compras de todos los usuarios, he añadido un archivo llamado order.model.ts en el src / app / modelo carpeta y definido el código que se muestra en
el Listado 8-20 .
153
Capítulo 8 ■ Spor tSStore: órdenes y salida
@Injectable ()
Orden de la clase {exportación
claro() {
this.id = null;
this.name = this.address = this.city = null; this.state = this.zip =
this.country = null; this.shipped = false; this.cart.clear (); }}
los Orden clase será otro servicio, lo que significa que habrá una instancia compartida en toda la aplicación. Cuando angular
crea la Orden objeto, se detectará el Carro parámetro constructor y proporcionar la misma Carro objeto que se utiliza en otras partes
de la aplicación.
Para gestionar los pedidos en la aplicación, lo que necesito para extender el repositorio y la fuente de datos para que puedan recibir
Orden objetos. Listado 8-21 agrega un método a la fuente de datos que recibe una orden. Dado que este sigue siendo la fuente de datos ficticios, el
método simplemente produce una cadena JSON de la orden y lo escribe en la consola de JavaScript. Voy a hacer algo más útil con los objetos de la
sección siguiente cuando se crea un origen de datos que utiliza peticiones HTTP para comunicarse con el servicio web REST.
Listado 8-21. Manejo de pedidos de los static.datasource.ts archivo en la carpeta src / app / modelo
@Injectable ()
StaticDataSource clase de exportación {
productos privados de producto: [] = [
nuevo producto (1, "Producto 1", "Categoría 1", "Producto 1 (Categoría 1)", 100), el nuevo producto (2,
"Producto 2", "Categoría 1", "Producto 2 (Categoría 1)" , 100), el nuevo producto (3, "Producto 3",
"Categoría 1", "Producto 3 (Categoría 1)", 100),
154
Capítulo 8 ■ Spor tSStore: órdenes y salida
nuevo producto (4, "Producto 4", "Categoría 1", "Producto 4 (Categoría 1)", 100), el nuevo producto (5,
"producto 5", "Categoría 1", "Producto 5 (categoría 1)" , 100), el nuevo producto (6, "Producto 6", "Categoría
2", "Producto 6 (categoría 2)", 100), el nuevo producto (7, "Producto 7", "Categoría 2", "Producto 7 ( categoría
2)", 100), el nuevo producto (8, "producto 8", "Categoría 2", "Producto 8 (categoría 2)", 100), el nuevo
producto (9, "Producto 9", "Categoría 2", "Producto 9 (categoría 2)", 100), el nuevo producto (10, "Producto
10", "Categoría 2", "Producto 10 (categoría 2)", 100), el nuevo producto (11, "Producto 11", " Categoría 3" ,
"Producto 11 (Categoría 3)", 100), el nuevo producto (12 "Producto 12" , "categoría 3", "producto 12
(Categoría 3)", 100), el nuevo producto (13, "producto 13", "categoría 3", "producto 13 (Categoría 3)", 100),
los productos nuevos (14 "14 del producto", "Categoría 3", "Producto 14 (Categoría 3)", 100), el nuevo
producto (15, "Producto 15", "categoría 3", "Producto 15 (Categoría 3)", 100 ),];
Para gestionar los pedidos, he añadido un archivo llamado order.repository.ts al src / app / modelo carpeta y lo utilizó para definir la clase de
muestra en el listado 8-22 . Sólo hay un método en el repositorio fin por el momento, pero voy a añadir más funcionalidad en el capítulo 9 cuando
creo las funciones de administración.
■ Propina Usted no tiene que utilizar diferentes repositorios para cada tipo de modelo en la aplicación, pero a menudo lo hacen porque una sola
clase responsable de múltiples tipos de modelos puede llegar a ser complejos y difíciles de mantener.
@Injectable ()
OrderRepository clase de exportación {
órdenes privadas: Solicitar [] = [];
155
Capítulo 8 ■ Spor tSStore: órdenes y salida
Listado 8-23 registra el Orden clase y el nuevo repositorio como servicios utilizando el proveedores propiedad del módulo de función del modelo.
Listado 8-23. Registro de Servicios en los model.module.ts archivo en la carpeta src / app / modelo
@NgModule ({
proveedores: [ProductRepository, StaticDataSource, Carro,
Orden, OrderRepository]
})
ModelModule clase de exportación {}
El siguiente paso es reunir los datos del usuario requerido para completar el pedido. Angular incluye directivas incorporadas para trabajar con
formularios HTML y validar su contenido. Listado 8-24 se prepara el componente de checkout, el cambio a una plantilla externa, la recepción de
la Orden objeto como un parámetro de constructor, y proporcionar un apoyo adicional para ayudar a la plantilla.
Listado 8-24. Preparación para un formulario en el archivo checkout.component.ts en la carpeta src / app / tienda
@Componente({
templateUrl: "checkout.component.html", styleUrls:
[ "checkout.component.css"]
})
CheckoutComponent clase de exportación {
orderSent: boolean = false;
presentado: boolean = false;
156
Capítulo 8 ■ Spor tSStore: órdenes y salida
this.submitted = true; si
(form.valid) {
this.repository.saveOrder (this.order) .subscribe (orden => {
this.order.clear ();
this.orderSent = true; this.submitted
= false; }); }}
los orden de envio método será invocado cuando el usuario envía un formulario, que está representado por una NgForm objeto.
Si los datos que contiene el formulario es válido, entonces el Orden objeto se pasa al repositorio de saveOrder método, y los datos en el
carro y el orden se restablecerá.
Los @ Componente decorador de styleUrls propiedad se utiliza para especificar una o más hojas de estilo CSS que se deben aplicar a los contenidos
en la plantilla del componente. Para proporcionar comentarios de validación de los valores que el usuario entra en los elementos de formulario HTML, he
creado un archivo llamado checkout.component.css en el
src / app / tienda carpeta y define los estilos que se muestran en el Listado 8-25 .
Listado 8-25. Los contenidos del archivo checkout.component.css en la carpeta src / app / tienda
Angular agrega elementos a la ng-sucio, ng-válida, y ng-válido clases para indicar su estado de validación. El conjunto completo de clases de
validación se describe en el capítulo 14 , Pero el efecto de los estilos en venta 8-25 es añadir un borde verde alrededor entrada elementos que son
válidos y un borde rojo alrededor de los que no son válidos.
La pieza final del rompecabezas es la plantilla para el componente, que presenta al usuario con los campos de formulario necesarios para poblar las
propiedades de una Orden objeto, como se muestra en el listado 8-26 .
Listado 8-26. Los contenidos del archivo checkout.component.html en la carpeta src / app / tienda
157
Capítulo 8 ■ Spor tSStore: órdenes y salida
<Span * ngIf = "presentado && name.invalid" class = "text-peligro"> Por favor, introduzca su
nombre </ span> </ div>
158
Capítulo 8 ■ Spor tSStore: órdenes y salida
los formar y entrada elementos en esta plantilla utilizan características angulares para asegurar que el usuario proporciona los valores para cada campo,
y proporcionan retroalimentación visual si el usuario hace clic en el botón Completar pedido sin completar el formulario. Parte de esta información proviene de
la aplicación de los estilos que se han definido en el Listado 8-25 Y parte proviene de lapso elementos que permanecen ocultos hasta que el usuario intenta
enviar una forma inválida.
■ Propina requiriendo valores es sólo una de las formas en que puede validar angular campos de formulario, y como he explicado en el capítulo 14 ,
Para ver el proceso, comenzar con la lista de productos y haga clic en uno de los botones Añadir al carro para agregar un producto a la
cesta. Haga clic en el botón Checkout y verá el formulario HTML se muestra en la figura 8-6 . Haga clic en el botón Completar Orden sin introducir
texto en cualquiera de los entrada elementos, y verá los mensajes de información de validación. Rellene el formulario y haga clic en el botón
Completar Orden; verá el mensaje de confirmación que se muestra en la figura.
159
Capítulo 8 ■ Spor tSStore: órdenes y salida
Si nos fijamos en la consola JavaScript del navegador, verá una representación JSON de la orden de la siguiente manera:
{"carro":
{"líneas":[
{ "Producto": { "id": 1, "name": "Producto 1", "categoría": "Categoría 1", "Descripción": "Producto
1 (Categoría 1)", "precio": 100}, "cantidad": 1}], "objetoCuenta": 1, "cartPrice": 100}, "enviado":
false,
@Injectable ()
RestDataSource clase de exportación
{baseUrl: string;
160
Capítulo 8 ■ Spor tSStore: órdenes y salida
Angular proporciona un servicio incorporado llamado HttpClient que se utiliza para realizar peticiones HTTP. los
RestDataSource constructor recibe el HttpClient servicio y utiliza el mundial ubicación objeto proporcionado por el navegador para determinar
la URL que las solicitudes serán enviados a, que es el puerto 3500 en el mismo host que la aplicación se ha cargado desde.
Los métodos definidos por la RestDataSource clase corresponden a los definidos por la fuente de datos estáticos pero se
implementan utilizando la HttpClient servicio, descrito en el capítulo 24 .
■ Propina Cuando la obtención de datos a través de HTTP, es posible que la congestión de red o carga del servidor retrasarán la solicitud y dejar que el
usuario busca en una aplicación que no tiene datos. en el capítulo 27 , Explico cómo configurar el sistema de enrutamiento para evitar este problema.
Para completar este capítulo, voy a aplicar la fuente de datos REST volviendo a configurar la aplicación para que el cambio de los datos
ficticios a los datos resto se hace con los cambios en un solo archivo. Listado 8-28
cambia el comportamiento del servicio de fuente de datos en el módulo de función del modelo.
Listado 8-28. Cambio de la configuración de servicio en las model.module.ts archivo en la carpeta src / app / modelo
@NgModule ({
importaciones: [HttpClientModule],
proveedores: [ProductRepository, Carro, Orden, OrderRepository, {proporcionar:
StaticDataSource, useClass: RestDataSource}]
})
ModelModule clase de exportación {}
los importaciones la propiedad se utiliza para declarar una dependencia en el HttpClientModule módulo de función, que proporciona la HttpClient servicio
utilizado en el Listado 8-27 . El cambio en el proveedores propiedad dice angular que cuando se necesita para crear una instancia de una clase con una StaticDataSo
parámetro constructor, se debe utilizar una RestDataSource en lugar. Dado que ambos objetos definen los mismos métodos, el sistema de tipos
JavaScript dinámica significa que la sustitución es perfecta. Cuando todos los cambios se han guardado y el navegador vuelve a cargar la aplicación,
verá los datos ficticia ha sido sustituido por los datos obtenidos a través de HTTP, como se muestra en la figura 8-7 .
161
Capítulo 8 ■ Spor tSStore: órdenes y salida
Si usted pasa por el proceso de selección de productos y la salida, se puede ver que la fuente de datos ha escrito la orden al servicio
web mediante la navegación a esta URL:
Esto mostrará todo el contenido de la base de datos, incluida la recogida de pedidos. Usted no será capaz de solicitar la / pedidos URL,
ya que requiere autenticación, que he creado en el siguiente capítulo.
■ Propina recordar que los datos proporcionados por el servicio web REST se restablece cuando se detiene el servidor y empezar de nuevo con el NPM
162
Capítulo 8 ■ Spor tSStore: órdenes y salida
Resumen
En este capítulo, continué la adición de características a la aplicación SportsStore, añadiendo soporte para un carro de compras en el que el usuario
puede colocar los productos y un proceso de pago que completa el proceso de compra. Para completar el capítulo, que sustituyó a la fuente de datos
ficticios con uno que envía peticiones HTTP al servicio web REST. En el siguiente capítulo, puedo crear las funciones de administración que permiten a
los datos SportsStore a ser gestionados.
163
CAPÍTULO 9
SportsStore: Administración
En este capítulo, continúo la construcción de la aplicación SportsStore mediante la adición de funciones de administración. Relativamente pocos usuarios
necesitan acceder a las funciones de administración, por lo que sería un desperdicio de forzar a los usuarios a descargar el código de la administración y el
contenido cuando es probable que se utilice. En su lugar, voy a poner las funciones de administración en un módulo separado que se cargarán sólo cuando se
requiere la administración.
Abrir una segunda línea de comandos y ejecute el comando siguiente en el Tienda de deportes carpeta para iniciar las herramientas de desarrollo
y servidor HTTP:
■ Propina Puede descargar el proyecto de ejemplo para este capítulo, y para todos los demás capítulos de este libro: de https://github.com/Apress/pro
.
Crear el módulo
El proceso para crear el módulo de función sigue el mismo patrón que ha visto en los capítulos anteriores. La diferencia clave es que es
importante que ninguna otra parte de la aplicación tiene dependencias en el módulo o las clases que contiene, lo que socavaría la carga
dinámica del módulo y hacer que el módulo de JavaScript para cargar el código de la administración, incluso si se trata no utilizado.
El punto de partida para las funciones de administración será de autenticación, que se asegurará de que sólo los usuarios autorizados son
capaces de administrar la aplicación. He creado un archivo llamado auth.component.ts en el
src / app / admin carpeta y lo utilizó para definir el componente de muestra en el listado 9-1 .
Listado 9-1. El contenido de los auth.component.ts archivo en la carpeta src / app / admin
@Componente({
templateUrl: "auth.component.html"})
El componente define propiedades para el nombre de usuario y contraseña que se utilizan para autenticar el usuario, una mensaje de
error propiedad que se utiliza para mostrar mensajes cuando hay problemas, y un
autenticar método que va a realizar el proceso de autenticación (pero que no hace nada por el momento).
Para proporcionar el componente con una plantilla, he creado un archivo llamado auth.component.html en el src / app / admin carpeta y añade el
contenido se muestra en el Listado 9-2 .
Listado 9-2. El contenido del archivo auth.component.html en el directorio src / aplicación de carpeta / admin
166
Capítulo 9 ■ SportSStore: Administración
La plantilla contiene un formulario HTML que utiliza expresiones de las propiedades del componente de enlace de datos bidireccionales. Hay un
botón que va a enviar el formulario, un botón que navega a la dirección URL de la raíz, y una
div elemento que es visible sólo cuando hay un mensaje de error para mostrar.
Para crear un marcador de posición para las funciones de administración, he añadido un archivo llamado admin.component.ts en el
El componente no contiene ninguna funcionalidad en el momento. Para proporcionar una plantilla para el componente, he añadido un archivo
llamado admin.component.html al src / app / admin carpeta y el contenido marcador de posición se muestra en el Listado 9-4 .
Listado 9-4. Los contenidos del archivo admin.component.html en el src / aplicación de carpeta / admin
Para definir el módulo de función, he añadido un archivo llamado admin.module.ts en el src / app / admin carpeta y añade el código del
listado 9-5 .
167
Capítulo 9 ■ SportSStore: Administración
@NgModule ({
importaciones: [CommonModule, FormsModule, enrutamiento],
declaraciones: [AuthComponent, AdminComponent]})
los RouterModule.forChild método se utiliza para definir la configuración de enrutamiento para el módulo de función, que luego se incluye en la década de
los módulos importaciones propiedad.
Un módulo cargado dinámicamente debe ser autónomo y incluir toda la información que requiere angular, incluyendo los URL de enrutamiento
que están soportadas y los componentes que se vea. Si cualquier otra parte de la aplicación depende del módulo, a continuación, se incluye en el
paquete de JavaScript con el resto del código de la aplicación, lo que significa que todos los usuarios tendrán que descargar el código y recursos
para las funciones que no van a utilizar.
Sin embargo, se permite que un módulo cargado dinámicamente para declarar dependencias en la parte principal de la aplicación. Este módulo se basa en
la funcionalidad del módulo de modelo de datos, que se ha añadido a la década de los módulos importaciones por lo que los componentes pueden tener acceso a
las clases del modelo y los repositorios.
módulos cargados dinámicamente son administrados a través de la configuración de enrutamiento, lo que desencadena el proceso de carga cuando la aplicación
se desplaza a un URL específico. Listado 9-6 se extiende la configuración de enrutamiento de la aplicación para que el / administración URL se carga el módulo de
función de administración.
Listado 9-6. Configuración de un módulo cargado dinámicamente en el Archivo app.module.ts en la carpeta src / app
@NgModule ({
importaciones: [BrowserModule, StoreModule,
RouterModule.forRoot ([
{
ruta: "tienda", componente: StoreComponent, canActivate:
[StoreFirstGuard]}, {
168
Capítulo 9 ■ SportSStore: Administración
{
ruta: "admin",
loadChildren: "./admin/admin.module#AdminModule",
canActivate: [StoreFirstGuard]},
proveedores: [StoreFirstGuard],
declaraciones: [AppComponent], de
arranque: [AppComponent]})
La nueva ruta angular dice que cuando la aplicación navega a la / administración URL, debe cargar un módulo de función definido por una clase
llamada AdminModule desde el admin / admin.module.ts archivo, cuyo camino se especifica en relación con el app.module.ts expediente. Cuando los
procesos angular del módulo de administración, incorporará la información de enrutamiento que contiene en el conjunto global de rutas y completar la
navegación.
Listado 9-7. La adición de un botón de navegación en el archivo store.component.html en la carpeta src / app / tienda
<Clase de botón = "btn btn-bloque-BTN peligro mt-3" routerLink = "/ admin"> Administrador </ botón>
</ Div>
169
Capítulo 9 ■ SportSStore: Administración
Para reflejar los cambios, se detiene las herramientas de desarrollo y reiniciarlos ejecutando el siguiente comando en el Tienda de deportes carpeta:
Utilizar el navegador para navegar hasta http: // localhost: 3000 y el uso de herramientas de desarrollo F12 de tu navegador para ver las peticiones de red
realizadas por el navegador cuando se carga la aplicación. Los archivos para el módulo de administración no se cargará hasta que haga clic en el botón de
administración, y en ese momento angular solicitará los archivos y mostrar la página de inicio de sesión se muestra en la figura 9-1 .
170
Capítulo 9 ■ SportSStore: Administración
Introducir el nombre y la contraseña en los campos del formulario y haga clic en el botón Iniciar sesión para ver el contenido marcador de posición, como se
muestra en la figura 9-2 . Si deja cualquiera de los campos de formulario vacío, se mostrará un mensaje de advertencia.
autenticación de Ejecución
El servicio web REST se ha configurado para que requiera autenticación para las peticiones que la función de administración requerirá. En
las secciones que siguen, agrego soporte para la autenticación del usuario mediante el envío de una petición HTTP al servicio web REST.
Tabla 9-1. Las credenciales de autenticación soportados por el servicio web REST
administración secreto
Como he señalado en el capítulo 7 , No debe credenciales de código duro en proyectos reales, pero este es el nombre de usuario
171
Capítulo 9 ■ SportSStore: Administración
Si las credenciales correctas se envían al / iniciar sesión URL, entonces la respuesta del servicio web REST contendrá un objeto JSON
como esto:
{
"Éxito": true,
"Token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoiYWRtaW4iLCJleHBpcmVz
SW4iOiIxaCIsImlhdCI6MTQ3ODk1NjI1Mn0.lJaDDrSu-bHBtdWrz0312p_DG5tKypGv6cA NgOyzlg8"
los éxito propiedad describe el resultado de la operación de autenticación y el simbólico propiedad contiene el JWT, que debe ser
incluido en las solicitudes posteriores utilizando el Autorización cabecera HTTP en este formato:
He configurado los tokens JWT devueltos por el servidor para que expiran después de una hora.
Si las credenciales incorrectas se envían al servidor, entonces el objeto JSON devuelto en la respuesta sólo va a
contener una propiedad éxito se define como false, como este:
{
"Éxito": false}
La fuente de datos REST va a hacer la mayor parte de la obra, ya que se encarga de enviar la solicitud de autenticación a la / iniciar sesión URL
e incluyendo el JWT en las solicitudes posteriores. Listado 9-8 añade autenticación a la RestDataSource clase y define una variable que
almacenará la JWT, una vez que se ha obtenido.
Listado 9-8. La adición de Autenticación en el rest.datasource.ts archivo en la carpeta src / app / modelo
172
Capítulo 9 ■ SportSStore: Administración
@Injectable ()
RestDataSource clase de exportación {
baseUrl: string;
auth_token: string;
@Injectable ()
AuthService clase de exportación {
173
Capítulo 9 ■ SportSStore: Administración
claro() {
this.datasource.auth_token = null; }}
los autenticar método recibe las credenciales del usuario y las transmite a la fuente de datos
autenticar método, devolver un Observable que producirá cierto si el proceso de autenticación ha tenido éxito y falso de otra manera. los autenticado
la propiedad es una propiedad de sólo captador que devuelve cierto Si la fuente de datos ha obtenido un token de autenticación. los claro método
elimina el token de la fuente de datos.
Listado 9-10 registra el nuevo servicio con el módulo de función del modelo. También agrega una proveedores entrada para el RestDataSource clase,
que sólo se ha utilizado como un sustituto de la StaticDataSource clase en los capítulos anteriores. Desde el AuthService clase tiene una RestDataSource parámetro
de constructor, que necesita su propia entrada en el módulo.
Listado 9-10. Configuración de los servicios en los model.module.ts archivo en la carpeta src / app / modelo
@NgModule ({
importaciones: [HttpClientModule],
proveedores: [ProductRepository, Carro, Orden, OrderRepository, {proporcionar:
StaticDataSource, useClass: RestDataSource}, RestDataSource, AuthService]
})
ModelModule clase de exportación {}
Listado 9-11. Habilitación de la autenticación en los auth.component.ts archivo en la carpeta src / app / admin
@Componente({
templateUrl: "auth.component.html"})
174
Capítulo 9 ■ SportSStore: Administración
} Else {
this.errorMessage = "Formulario de datos no válido"; }}}
Para evitar que la aplicación navegar directamente a las funciones de administración, lo que conducirá a las peticiones HTTP que se envían
sin una ficha, he añadido un archivo llamado auth.guard.ts en el src / app / admin carpeta y definido el guardia ruta mostrada en el Listado 9-12 .
@Injectable ()
clase de exportación AuthGuard {
if (! this.auth.authenticated) {
this.router.navigateByUrl ( "/ admin / auth"); falso retorno;
}
return true; }}
175
Capítulo 9 ■ SportSStore: Administración
Listado 9-13 se aplica el protector de ruta a una de las rutas definidas por el módulo de función de administración.
El listado 9-13. Protección de una ruta en el archivo admin.module.ts en la carpeta src / app / admin
@NgModule ({
importaciones: [CommonModule, FormsModule, enrutamiento],
proveedores de: [], AuthGuard
declaraciones: [AuthComponent, AdminComponent]})
Para probar el sistema de autenticación, haga clic en el botón de administrador, introduce algunas credenciales y haga clic en el botón Iniciar sesión.
Si las credenciales son los de la tabla 9-1 , A continuación, podrás ver el marcador de posición para las funciones de administración. Si introduce otras
credenciales, verá un mensaje de error. Figura 9-3 ilustra tanto los resultados.
176
Capítulo 9 ■ SportSStore: Administración
■ Propina el token no se almacena persistentemente, lo que si puede, vuelva a cargar la aplicación en el navegador para empezar de nuevo y probar
Listado 9-14. La adición de nuevas operaciones en los rest.datasource.ts archivo en la carpeta src / app / modelo
@Injectable ()
RestDataSource clase de exportación {
baseUrl: string;
auth_token: string;
177
Capítulo 9 ■ SportSStore: Administración
getOptions privadas () {
regreso {
encabezados: nuevos HttpHeaders ({
Listado 9-15 agrega nuevos métodos a la clase repositorio del producto que permiten que los productos pueden crear, actualizar o eliminar.
los saveProduct método es responsable de la creación y actualización de productos, que es un enfoque que funciona bien cuando se utiliza un
único objeto administrado por un componente, que usted verá demostrado más adelante en este capítulo. La lista también cambia el tipo del
argumento del constructor de
RestDataSource.
Listado 9-15. La adición de nuevas operaciones en los product.repository.ts archivo en la carpeta src / app / modelo
178
Capítulo 9 ■ SportSStore: Administración
@Injectable ()
ProductRepository clase de exportación {
productos privados: Producto [] = []; privadas
categorías: string [] = [];
this.dataSource.updateProduct (producto)
. suscribirse (p => {
this.products.splice (this.products.
FindIndex (p => p.id == product.id), 1, del producto); }); }}
Listado 9-16 hace que los correspondientes cambios en el repositorio de orden, la adición de métodos que permiten órdenes a ser modificados
y borrados.
179
Capítulo 9 ■ SportSStore: Administración
Listado 9-16. La adición de nuevas operaciones en los order.repository.ts archivo en la carpeta src / app / modelo
@Injectable ()
OrderRepository clase de exportación {
órdenes privadas: Solicitar [] = [];
privado cargado: boolean = false;
loadOrders () {
this.loaded = true;
this.dataSource.getOrders ()
. suscribirse (órdenes => = this.orders órdenes); }
this.orders regresar; }
El repositorio orden define una loadOrders método que obtiene las órdenes del repositorio, y que se utiliza para asegurarse de
que la solicitud no se envía al servicio web REST hasta que la autenticación se ha realizado.
180
Capítulo 9 ■ SportSStore: Administración
Nombre Descripción
/ admin / / productos principales Navegando a esta URL mostrará todos los productos en una tabla, junto con los botones que
permiten a un producto existente para ser editado o borrado y un nuevo producto que se creará.
/ Admin / main / productos / crean Navegando a esta URL presentará al usuario con un editor de vacío para crear un nuevo
producto.
/ Admin / main / productos / editar / 1 Navegando a esta URL presentará al usuario con un editor poblada para la edición de un producto
existente.
/ admin / main / órdenes Navegando a esta URL presentará al usuario con todos los pedidos en una mesa, junto con los
botones para marcar una orden enviada, y para cancelar un pedido si la elimina.
Me parece la forma más fácil de agregar características a un proyecto angular es definir los componentes que tienen contenido marcador de posición y
construyen la estructura de la aplicación que les rodea. Una vez que la estructura está en su lugar, y luego vuelvo a los componentes y poner en práctica las
características en detalle. Para las funciones de administración, empecé mediante la adición de un archivo llamado productTable.component.ts al src / app / admin carpeta
y se define el componente de muestra en el listado 9-17 . Este componente será responsable de mostrar una lista de productos, junto con los botones necesarios
para editar y eliminarlos o para crear un nuevo producto.
@Componente({
Plantilla: `<div class = "bg-info p-2-texto blanco">
<H3> Producto Tabla marcador de posición </ h3> </ div> `
})
ProductTableComponent clase de exportación {}
He añadido un archivo llamado productEditor.component.ts en el src / app / admin carpeta y lo utilizó para definir el componente de muestra en el listado 9-18
, El cual será utilizado para permitir que el usuario introduzca los datos necesarios para crear o editar un componente.
181
Capítulo 9 ■ SportSStore: Administración
@Componente({
Plantilla: `<div class = "bg-advertencia p-2-texto blanco">
<H3> Producto Editor de marcador de posición </ h3> </ div> `
})
ProductEditorComponent clase de exportación {}
Para crear el componente que será responsable de la gestión de pedidos de los clientes, he añadido un archivo llamado
orderTable.component.ts al src / app / admin carpeta y añade el código del listado 9-19 .
@Componente({
Plantilla: `<div class = "bg-primaria p-2-texto blanco">
<H3> orden de la tabla de marcador de posición </ h3> </
div> `
})
OrderTableComponent clase de exportación {}
Listado 9-20. Sustitución del contenido en el archivo admin.component.html en el directorio src / aplicación de carpeta / admin
182
Capítulo 9 ■ SportSStore: Administración
Esta plantilla contiene una enrutador de salida elemento que se utilizará para mostrar los componentes de la sección anterior.
También hay botones que navegar por la aplicación a la / admin / / productos principales
y / admin / main / órdenes URL, que seleccionará los productos o pedidos características. Estos botones utilizan el
routerLinkActive atributo, que se utiliza para agregar el elemento a una clase CSS cuando la ruta especificada por el
routerLink atributo está activo.
La plantilla contiene también una Cerrar sesión botón que tiene un suceso de unión que se dirige a un método llamado
cerrar sesión. Listado 9-21 añade este método para el componente, que utiliza el servicio de autenticación para eliminar el token al portador y se
desplaza la aplicación a la URL predeterminada.
Listado 9-21. La implantación del método Salir en los admin.component.ts archivo en la carpeta src / app / admin
@Componente({
templateUrl: "admin.component.html"})
cerrar sesión() {
this.auth.clear ();
this.router.navigateByUrl ( "/"); }
Listado 9-22 permite a los componentes de marcador de posición que se utilizarán para cada función de administración y se extiende la configuración
URL de enrutamiento para implementar las URL de la tabla 9-2 .
Listado 9-22. Configuración del módulo de funciones en el archivo admin.module.ts en la carpeta src / app / admin
183