En este tutorial, continuaremos construyendo nuestra aplicación de visor de juegos y agregaremos nuevas funciones a medida que avanzamos. Veremos cómo podemos usar el enlace de datos de propiedad para establecer propiedades de imagen en nuestro componente, luego las usaremos en la plantilla para mostrar una imagen para cada juego. A partir de ahí, usaremos el enlace de eventos para permitir que el usuario haga clic en un botón que hará que la imagen desaparezca y luego vuelva a aparecer. Después de eso, revisaremos el enlace bidireccional con ngModel y un elemento de entrada. Finalmente, veremos cómo se pueden usar Pipes en Angular para transformar datos enlazados.
Vinculación de propiedad para mostrar una imagen
En el componente podemos usar el enlace de propiedad para establecer el ancho de la imagen, así como el margen de la imagen que mostraremos para nuestros juegos.
game-list.component.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | import {Component} from '@angular/core'; @Component({ selector: 'game-list', templateUrl: './game-list.component.html' }) export class GameListComponent { pageTitle = 'Dynamic! Game List'; imageWidth = 45; imageMargin = 1; games = [ { "gameId": 1, "gameName": "Castlevania", "gameCode": "AAA-0101", "releaseDate": "September 26, 1986", "description": "Action-adventure game series created and developed by Konami.", "price": 19.99, "thumbRating": 5.0, "imageUrl": "./assets/images/castlevania.png" }, { "gameId": 2, "gameName": "Dr Mario", "gameCode": "AAA-1100", "releaseDate": "July 27, 1990", "description": "Action puzzle game produced by Gunpei Yokoi and published by Nintendo.", "price": 15.99, "thumbRating": 3, "imageUrl": "./assets/images/drmario.png" }, { "gameId": 3, "gameName": "Kid Icarus", "gameCode": "AAA-0048", "releaseDate": "December 19, 1986", "description": "Kid Icarus revolves around protagonist Pit's quest for three sacred treasures.", "price": 20.99, "thumbRating": 4, "imageUrl": "./assets/images/kidicarus.png" }, { "gameId": 4, "gameName": "Legend Of Zelda", "gameCode": "AAA-0049", "releaseDate": "February 21, 1986", "description": "Link is often given the task of rescuing Princess Zelda and the kingdom of Hyrule from Ganon.", "price": 29.95, "thumbRating": 5, "imageUrl": "./assets/images/legendofzelda.png" }, { "gameId": 7, "gameName": "Super Mario Bros", "gameCode": "AAA-3325", "releaseDate": "September 13, 1985", "description": "Mario finds power-ups and items that give him special magic powers such as fireball-throwing and size-changing into giant and miniature sizes.", "price": 40.95, "thumbRating": 5, "imageUrl": "./assets/images/supermariobros.png" } ]; } |
Luego, en el archivo de plantilla asociado, se puede acceder a esas propiedades de clase usando la sintaxis [attributename] = 'attributevalue' . Tenga en cuenta que los atributos src y title provienen de las propiedades de la clase, mientras que el ancho y el margen provienen de esos datos json en la matriz de juegos.
game-list.component.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | <div class='card'> <div class='card-header'> {{pageTitle}} </div> <div class='card-body'> <div class="row"> <div class="col-3"> <input type="text" class="form-control" id="filterInput" placeholder="Type to filter"> </div> <div class="col"> <div class="form-text text-muted">Filtered by:</div> </div> </div> <div class='table-responsive'> <table class='table' *ngIf='games && games.length'> <thead> <tr> <th> <button class='btn btn-primary'> Hide Image </button> </th> <th>Game</th> <th>Part#</th> <th>Release Date</th> <th>Cost</th> <th>5 Thumb Rating</th> </tr> </thead> <tbody> <tr *ngFor='let game of games'> <td> <img [src]='game.imageUrl' [title]='game.gameName' [style.width.px]='imageWidth' [style.margin.px]='imageMargin'> </td> <td>{{ game.gameName }}</td> <td>{{ game.gameCode }}</td> <td>{{ game.releaseDate }}</td> <td>{{ game.price }}</td> <td>{{ game.thumbRating }}</td> </tr> </tbody> </table> </div> </div> <div class="card-footer text-muted text-right"> <small>Powered by Angular</small> </div> </div> |
¡Ok, ahora tenemos imágenes para nuestros juegos!
Enlace de eventos para responder al clic del botón
Recuerde que la vinculación de eventos es el acto de escuchar que suceda un evento en el DOM y luego enviar un mensaje al código del componente cuando se activa el evento. En el componente, podemos configurar una propiedad de showImage
y establecerla en verdadero o falso para mostrar o no mostrar la imagen. De forma predeterminada, se mostrará, por lo que se establece en verdadero. Además, agregamos el toggleImage()
método que simplemente muestra una imagen si no hay ninguna, o la elimina si ya está presente.
game-list.component.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import {Component} from '@angular/core'; @Component({ selector: 'game-list', templateUrl: './game-list.component.html' }) export class GameListComponent { pageTitle = 'Dynamic! Game List'; imageWidth = 45; imageMargin = 1; showImage = true; games = [...]; toggleImage(): void { this.showImage = !this.showImage; } } |
La plantilla ahora tendrá un clic incluso registrado a través de (clic) = 'toggleImage ()' , y luego un operador ternario simple cambiará el texto dentro del botón según si hay una imagen presente o no con {{showImage? 'Ocultar': 'Mostrar'}} Imagen . Un operador ternario es como un atajo para una declaración if. El código aquí dice si la imagen está presente, entonces muestra "Ocultar". Si la imagen no está allí, muestre "Mostrar". Usamos esto en combinación con la directiva estructural* ngIf que aprendimos recientemente acerca de agregar o eliminar dinámicamente el elemento <img> del dom.
game-list.component.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | <div class='card'> <div class='card-header'> {{pageTitle}} </div> <div class='card-body'> <div class="row"> <div class="col-3"> <input type="text" class="form-control" id="filterInput" placeholder="Type to filter"> </div> <div class="col"> <div class="form-text text-muted">Filtered by:</div> </div> </div> <div class='table-responsive'> <table class='table' *ngIf='games && games.length'> <thead> <tr> <th> <button class='btn btn-primary' (click)='toggleImage()'> {{showImage ? 'Hide ' : 'Show'}} Image </button> </th> <th>Game</th> <th>Part#</th> <th>Release Date</th> <th>Cost</th> <th>5 Thumb Rating</th> </tr> </thead> <tbody> <tr *ngFor='let game of games'> <td> <img *ngIf='showImage' [src]='game.imageUrl' [title]='game.gameName' [style.width.px]='imageWidth' [style.margin.px]='imageMargin'> </td> <td>{{ game.gameName }}</td> <td>{{ game.gameCode }}</td> <td>{{ game.releaseDate }}</td> <td>{{ game.price }}</td> <td>{{ game.thumbRating }}</td> </tr> </tbody> </table> </div> </div> <div class="card-footer text-muted text-right"> <small>Powered by Angular</small> </div> </div> |
Aquí está el resultado que obtenemos.
Encuadernación bidireccional
Angular usa una sintaxis conocida como Banana In A Box para significar un enlace bidireccional. Se nombra un plátano en una caja a causa de esta sintaxis: [()]
. Usaremos esa sintaxis para configurar el enlace de datos bidireccional en la entrada de texto que se usará para filtrar la lista de juegos. Por el momento, no tenemos configurado el filtrado, pero podemos ver cómo funciona el enlace bidireccional a continuación. Primero necesitamos importar el FormsModule en app.module.ts, de lo contrario habrá errores como No se puede enlazar a ngModel ya que no es una entrada de propiedad conocida .
app.module.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import {NgModule} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {FormsModule} from '@angular/forms'; import {AppComponent} from './app.component'; import {GameListComponent} from './games/game-list.component'; @NgModule({ declarations: [ AppComponent, GameListComponent ], imports: [ BrowserModule, FormsModule ], bootstrap: [AppComponent] }) export class AppModule { } |
En el componente, agregamos una nueva propiedad de clase de listItem
. Esto se vinculará a la entrada de texto en la plantilla para que cuando el valor cambie en la plantilla, el valor en la clase también se actualice.
game-list.component.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import {Component} from '@angular/core'; @Component({ selector: 'game-list', templateUrl: './game-list.component.html' }) export class GameListComponent { pageTitle = 'Dynamic! Game List'; imageWidth = 45; imageMargin = 1; showImage = true; listItem = 'Mario'; games = [... ]; toggleImage(): void { this.showImage = !this.showImage; } } |
En la plantilla, esa propiedad ahora está vinculada usando [(ngModel)] = ”listItem” . Además, hacemos un buen uso de ese operador ternario nuevamente para cambiar si el texto al lado del cuadro de entrada muestra "Filtrado por" o "No filtrado".
game-list.component.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | <div class='card'> <div class='card-header'> {{pageTitle}} </div> <div class='card-body'> <div class="row"> <div class="col-3"> <input [(ngModel)]="listItem" type="text" class="form-control" id="filterInput" placeholder="Type to filter"> </div> <div class="col"> <div class="form-text text-muted"> {{listItem ? 'Filtered By:' : 'Not Filtered'}} {{listItem}} </div> </div> </div> <div class='table-responsive'> <table class='table' *ngIf='games && games.length'> <thead> <tr> <th> <button class='btn btn-primary' (click)='toggleImage()'> {{showImage ? 'Hide ' : 'Show'}} Image </button> </th> <th>Game</th> <th>Part#</th> <th>Release Date</th> <th>Cost</th> <th>5 Thumb Rating</th> </tr> </thead> <tbody> <tr *ngFor='let game of games'> <td> <img *ngIf='showImage' [src]='game.imageUrl' [title]='game.gameName' [style.width.px]='imageWidth' [style.margin.px]='imageMargin'> </td> <td>{{ game.gameName }}</td> <td>{{ game.gameCode }}</td> <td>{{ game.releaseDate }}</td> <td>{{ game.price }}</td> <td>{{ game.thumbRating }}</td> </tr> </tbody> </table> </div> </div> <div class="card-footer text-muted text-right"> <small>Powered by Angular</small> </div> </div> |
Puede ver que si hay un término de filtro en la entrada, el texto muestra "Filtrado por". Sin embargo, si eliminamos el término de filtro a ningún carácter, ahora se muestra como "Sin filtrar".
Tubo de moneda angular
Las tuberías son una buena característica para usar en Angular. Las tuberías proporcionan un medio para transformar datos enlazados en una plantilla angular. Hay varias tuberías integradas y también puede construir tuberías personalizadas si lo desea. Una tubería toma un valor y luego devuelve un valor. El uso más común es para transformaciones simples de datos. Primero veremos la canalización de moneda incorporada y la usaremos para formatear el precio de nuestros juegos. Verás que la sintaxis es muy simple.
game-list.component.html
| <tr *ngFor='let game of games'> <td> <img *ngIf='showImage' [src]='game.imageUrl' [title]='game.gameName' [style.width.px]='imageWidth' [style.margin.px]='imageMargin'> </td> <td>{{ game.gameName }}</td> <td>{{ game.gameCode }}</td> <td>{{ game.releaseDate }}</td> <td>{{ game.price | currency:'USD':'symbol':'1.2-2' }}</td> <td>{{ game.thumbRating }}</td> </tr> |
Tubo angular en minúsculas
Otra tubería ordenada es la tubería en minúsculas. A continuación, lo agregaremos para que todos los números de pieza o códigos de juego de cada juego se transformen de un formato de mayúsculas a un formato de minúsculas.
game-list.component.html
| <tr *ngFor='let game of games'> <td> <img *ngIf='showImage' [src]='game.imageUrl' [title]='game.gameName' [style.width.px]='imageWidth' [style.margin.px]='imageMargin'> </td> <td>{{ game.gameName }}</td> <td>{{ game.gameCode | lowercase }}</td> <td>{{ game.releaseDate }}</td> <td>{{ game.price | currency:'USD':'symbol':'1.2-2' }}</td> <td>{{ game.thumbRating }}</td> </tr> |
Resumen
A medida que agregamos funciones, trabajamos con los cuatro tipos diferentes de enlace en Angular que son Interpolación, Enlace de propiedades, Enlace de eventos y Enlace bidireccional. El gráfico a continuación muestra la dirección de cada tipo de enlace entre DOM (Plantilla) y Componente (Clase).
Si hay datos en la clase de componente que no están en el formato necesario para mostrarse en la plantilla, entonces puede utilizar Pipes para realizar una transformación de datos. Esto a menudo hace que la pantalla sea más fácil de usar para el usuario.
- El carácter Pipe
|
se usa para hacer uso de un Pipe - El nombre de la tubería es obligatorio, como
lowercase
- Los parámetros de la tubería están separados por dos puntos. Mire el ejemplo de moneda anterior para ver esto en acción
0 Comentarios