Cree un panel receptivo con material angular y gráficos ng2
Publicado: 2022-03-10Crear un tablero desde cero suele ser bastante complicado. Tienes que crear herramientas para recopilar datos sobre elementos de interés. Una vez recopilados, estos datos deben presentarse de una manera fácil de entender y significativa para sus usuarios. Implica una planificación compleja de qué datos incluir y cómo mostrarlos de manera efectiva. Una vez que tiene un plan, implementar el diseño es una tarea enorme, especialmente porque implica construir múltiples componentes.
Con Angular Material y ng2-charts, puede aprovechar los esquemas para reducir el esfuerzo y el tiempo que puede dedicar a crear un tablero. Angular Material se envía con una serie de esquemas que puede usar para generar un tablero. De manera similar, ng2-charts proporciona esquemas para generar múltiples componentes de gráficos. En este artículo, ilustraré cómo usar ng2-charts y Angular Material para configurar un tablero con bastante rapidez.
Un ejemplo
Para ilustrar cómo crear un tablero, tomaremos el ejemplo de una tienda en línea que vende artículos de cuero como bolsos, billeteras, llaveros, etc. Al dueño de la tienda le gustaría rastrear información como de dónde vienen los clientes a su tienda en línea, cómo se venden sus productos, cómo se relacionan las fuentes de tráfico con las ventas, entre otras cosas.
Crearemos un tablero para mostrar esta información y ayudar al propietario de la tienda a analizarla. El tablero contendrá cuatro pequeñas tarjetas de resumen, cuatro tipos diferentes de gráficos y una tabla que enumera los pedidos realizados más recientemente. Las cuatro tarjetas de resumen mostrarán información como los ingresos totales de las ventas, el valor promedio de los pedidos, la cantidad total de pedidos y la cantidad de clientes que regresan. Los gráficos mostrarán la cantidad de unidades vendidas de cada producto, las ventas por fuente de tráfico, las sesiones de la tienda en línea a lo largo del tiempo y las ventas de la semana.
requisitos previos
Para seguir, deberá tener instalado Angular CLI. Si no lo tiene instalado, puede averiguar cómo obtenerlo en cli.angular.io. Si no está comenzando desde un proyecto Angular preexistente, debe generar uno ejecutando ng new <your project name>
. Por ejemplo, para crear un panel de administración para la tienda antes mencionada, ejecutaremos:
ng new store-admin-panel
Su proyecto también necesita tener rutas configuradas para él. Si está comenzando desde una nueva aplicación, seleccione sí cuando se le pregunte si desea agregar un módulo de enrutamiento angular durante la configuración de su proyecto anterior.
Agregue material angular y gráficos Ng2 a su proyecto
Angular Material se envía con varios esquemas para generar una variedad de componentes útiles como libretas de direcciones, árboles, tablas, navegación, etc. Para agregar material angular a su proyecto, ejecute:
ng add @angular/material
Elija un tema de las opciones proporcionadas en las indicaciones posteriores. A continuación, se le pedirá que elija si desea agregar estilos tipográficos de material angular y animaciones del navegador. No los necesita y simplemente podría responder que no.
A continuación, deberá instalar ng2-charts. ng2-charts requiere charts.js como dependencia. Para instalar ng2-charts ejecute:
npm install ng2-charts --save
Luego instale charts.js:
npm install chart.js --save
Para acceder a los gráficos, agregue ChartsModule
a las importaciones de AppModule
.
import { ChartsModule } from 'ng2-charts'; @NgModule({ imports: [ … ChartsModule, … ] })
Por último, instale los esquemas de ng2-charts como una dependencia de desarrollo porque no se envían con ng2-charts de forma predeterminada.
npm install --save-dev ng2-charts-schematics
Generación de un componente de navegación
En primer lugar, necesitaremos agregar un componente de navegación para ayudar a los usuarios a moverse cómodamente por la aplicación. La navegación debe contener enlaces al tablero y otras páginas que formarán parte del panel de administración. El material angular proporciona un esquema que genera un componente de navegación. Llamaremos a este componente nav
. Agregar una navegación lateral a la aplicación se logra ejecutando:
ng generate @angular/material:navigation nav
Para vincular otras rutas en la navegación, use la directiva routerLink
y cambie el nombre de la página en la barra de herramientas según la ruta en la que se encuentre el usuario.
// nav.component.ts ... menuItems = ['dashboard', 'sales', 'orders', 'customers', 'products'];
<!--nav.component.html--> ... <mat-nav-list> <a *ngFor="let item of menuItems" mat-list-item [routerLink]="'/'+item"> {{item | titlecase}} </a> ...
Para ver este componente, agréguelo a app.component.html
.
<!--app.component.html--> <app-nav></app-nav>
Así es como se ve el NavComponent
.
Dado que la navegación se mostrará junto con otros componentes, agregarle una router-outlet
ayudaría a cambiar entre los otros componentes diferentes. En la plantilla nav.component.html
, justo después de cerrar </mat-toolbar>
, reemplace el comentario <!-- Add Content Here -->
con <router-outlet></router-outlet>
.
<!--nav.component.html--> <mat-sidenav-container> ... <mat-sidenav-content> <mat-toolbar> ... </mat-toolbar> <router-outlet></router-outlet> </mat-sidenav-content> </mat-sidenav-container>
En las capturas de pantalla que siguen en este artículo, este componente de navegación se omitirá para resaltar mejor el tablero que generaremos por el bien del tutorial. Si está siguiendo mientras crea este tablero, la navegación seguirá apareciendo como se muestra arriba en su navegador con el tablero dentro.
Generar el tablero
La parte más importante del tablero es su diseño. Debe contener todos los componentes mencionados anteriormente y responder cuando se muestra en diferentes dispositivos. Para generar el diseño del panel, deberá ejecutar el esquema @angular/material:dashboard
. Generará un componente de tablero receptivo. Pase el nombre preferido para su tablero al esquema. En este caso, llamémoslo dash
.
ng generate @angular/material:dashboard dash
Para ver el tablero recién generado dentro del componente de navegación, agregue una ruta al enrutador.
// app-routing.module.ts import { DashComponent } from './dash/dash.component'; const routes: Routes = [{ path: 'dashboard', component: DashComponent }]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] })
Una vez hecho esto, para ver los resultados, ejecute npm start
y diríjase a localhost:4200/dashboard
. Deberías ver esto:
El esquema genera cuatro tarjetas en la plantilla y las muestra en una cuadrícula receptiva. El CDK de material angular utiliza el paquete de Layout
para diseñar esta cuadrícula de tarjeta receptiva. La utilidad BreakpointObserver
del paquete Layout
evalúa las consultas de medios y realiza cambios en la interfaz de usuario en función de ellas. Hay varios puntos de interrupción disponibles, pero dentro del componente generado, solo se atienden dos categorías. El Breakpoints.Handset
y otras consultas que no coinciden. El paquete de Layout
especifica 14 estados de punto de interrupción que puede usar para personalizar la capacidad de respuesta de su tablero.
// dashboard.component.js ... cards = this.breakpointObserver.observe(Breakpoints.Handset).pipe( map(({ matches }) => { if (matches) { ... } ... }) );
Volviendo al tablero, dado que habrá cuatro tarjetas de resumen, cuatro gráficos y una tabla en el tablero, necesitamos nueve tarjetas en total. Las coincidencias de Breakpoints.Handset
y Breakpoints.Tablet
se mostrarán en una cuadrícula de una columna donde:
- Las cuatro tarjetas de resumen ocuparán una fila.
- Los gráficos abarcarán dos filas.
- La tabla abarcará cuatro filas.
Las coincidencias que no sean Breakpoints.Handset
y non- Breakpoints.Tablet
se mostrarán en cuatro columnas donde:
- Las cuatro tarjetas de resumen abarcarán una fila y una columna.
- Los gráficos abarcarán dos filas y dos columnas.
- La tabla tendrá cuatro filas y cuatro columnas.
Debería parecerse a la captura de pantalla a continuación en coincidencias que no sean Breakpoints.Handset
y que no Breakpoints.Tablet
. En las coincidencias Breakpoints.Handset
y Breakpoints.Tablet
, todo se mostrará en una sola columna.
Crear un componente de tarjeta
En el componente del tablero, todas las tarjetas se generan a través de la iteración. Para evitar repeticiones, al agregar todos los componentes nuevos, crearemos un componente de tarjeta reutilizable. El componente de la tarjeta aceptará un título como entrada y usará ng-content
para agregar dinámicamente el resto del contenido. Para crear el componente de la tarjeta, ejecute:
ng gc card -m app --style css
Desde la plantilla del componente del tablero, solo tomaremos el marcado incluido dentro de la etiqueta <mat-card>
y lo colocaremos en la plantilla de la tarjeta:
<!--card.component.html--> <mat-card class="dashboard-card"> <mat-card-header> <mat-card-title> {{title}} <button mat-icon-button class="more-button" [matMenuTriggerFor]="menu" aria-label="Toggle menu"> <mat-icon>more_vert</mat-icon> </button> <mat-menu #menu="matMenu" xPosition="before"> <button mat-menu-item>Expand</button> <button mat-menu-item>Remove</button> </mat-menu> </mat-card-title> </mat-card-header> <mat-card-content class="dashboard-card-content"> <ng-content></ng-content> </mat-card-content> </mat-card>
Para agregar el título como entrada a la tarjeta:
// card.component.ts import { Component, Input } from '@angular/core'; ... export class CardComponent{ @Input() title: string; ... }
Para aplicar estilo a la tarjeta:
/*card.component.css*/ .more-button { position: absolute; top: 5px; right: 10px; } .dashboard-card { position: absolute; top: 15px; left: 15px; right: 15px; bottom: 15px; } .dashboard-card-content { text-align: center; flex-grow: 1; display: flex; flex-direction: column; align-items: center; max-height: 100%; justify-content: center; align-items: stretch; } mat-card { display: flex; flex-direction: column; }
Agregar tarjetas al tablero
Dado que los elementos del tablero se agregarán individualmente y no a través de la iteración, el componente del tablero debe modificarse para tener esto en cuenta. En dashboard.component.ts
, elimine la propiedad de las cards
y reemplácela con una propiedad cardLayout
en su lugar. La variable cardLayout
definirá la cantidad de columnas para la lista de cuadrícula de materiales y cuántas filas y columnas abarcará cada una de las tarjetas del tablero. Las coincidencias de consultas Breakpoints.Handset
y Breakpoints.Tablet
se mostrarán en 1 columna y las que no coincidan se mostrarán en 4 columnas.
// dashboard.component.js ... cardLayout = this.breakpointObserver.observe(Breakpoints.Handset).pipe( map(({ matches }) => { if (matches) { return { columns: 1, miniCard: { cols: 1, rows: 1 }, chart: { cols: 1, rows: 2 }, table: { cols: 1, rows: 4 }, }; } return { columns: 4, miniCard: { cols: 1, rows: 1 }, chart: { cols: 2, rows: 2 }, table: { cols: 4, rows: 4 }, }; }) ); ...
En la plantilla dash.component.html
, reemplace los valores colspan
y rowspan
de los elementos mat-grid-tile
y la propiedad cols
del elemento mat-grid-list
.
<!--dash.component.html--> <div class="grid-container"> <h1 class="mat-h1">Dashboard</h1> <mat-grid-list cols="{{ ( cardLayout | async )?.columns }}" rowHeight="200px"> <!--Mini Cards--> <mat-grid-tile *ngFor="let i of [1, 2, 3, 4]" [colspan]="( cardLayout | async )?.miniCard.cols" [rowspan]="( cardLayout | async )?.miniCard.rows"> <app-card title="Card {{i}}"><div>Mini Card Content Here</div></app-card> </mat-grid-tile> <!--Charts--> <mat-grid-tile *ngFor="let i of [5, 6, 7, 8]" [colspan]="( cardLayout | async )?.chart.cols" [rowspan]="( cardLayout | async )?.chart.rows"> <app-card title="Card {{i}}"><div>Chart Content Here</div></app-card> </mat-grid-tile> <!--Table--> <mat-grid-tile [colspan]="( cardLayout | async )?.table.cols" [rowspan]="( cardLayout | async )?.table.rows"> <app-card title="Card 9"><div>Table Content Here</div></app-card> </mat-grid-tile> </mat-grid-list> </div>
El tablero terminará luciendo exactamente como la captura de pantalla más reciente vinculada arriba.
Generación de los gráficos
Los cuatro gráficos que necesitamos para el tablero son:
- Un gráfico de radar de productos por unidad vendida.
- Un gráfico circular de ventas por fuente de tráfico.
- Un gráfico de barras de las sesiones de la tienda en línea.
- Un gráfico de líneas de las ventas a lo largo del año.
De manera similar a la creación del tablero, la generación de componentes de gráficos implica la ejecución de un esquema. Usando los esquemas de ng2-charts, genere los cuatro gráficos diferentes. Los colocaremos en una carpeta llamada charts. Ejecute ng generate ng2-charts-schematics:<chart type> <chart name>
.
ng generate ng2-charts-schematics:radar charts/product-sales-chart ng generate ng2-charts-schematics:pie charts/sales-traffic-chart ng generate ng2-charts-schematics:line charts/annual-sales-chart ng generate ng2-charts-schematics:bar charts/store-sessions-chart
Después de ejecutar estos comandos, se generan los cuatro componentes del gráfico y se completan con datos de muestra listos para mostrar. Según los datos que desee mostrar, elija los gráficos que mejor se adapten a sus necesidades de visualización de datos. Para cada uno de los gráficos generados anteriormente, agregue la clase chartContainer
a los div
que encierran el elemento canvas
en las plantillas de gráficos.
<div class="chartContainer"> <canvas baseChart width="400" height="400"> ...
A continuación, agregue este estilo a styles.css
para que todos los componentes del gráfico puedan acceder a ellos.
/*styles.css*/ ... .chartContainer canvas { max-height: 250px; width: auto; } .chartContainer{ height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; }
Agregar datos a los gráficos
Los componentes del gráfico generado vienen con datos de muestra ya conectados. Si tiene servicios preexistentes que proporcionan sus propios datos, puede agregar estos datos a los componentes del gráfico. Los gráficos toman etiquetas para el eje x, datos o conjuntos de datos, un tipo de gráfico, colores, una leyenda y otras opciones de personalización. Para proporcionar los datos y las etiquetas a los gráficos, cree un servicio que obtenga datos de una fuente de su elección y los devuelva en una forma que acepten los gráficos. Por ejemplo, AnnualSalesChartComponent
recibe su conjunto de datos y etiquetas del método SalesService
de getSalesByMonth
que devuelve una matriz de ventas para cada mes del año actual. Puede encontrar este servicio aquí y los datos que devuelve aquí. Inyecte el servicio como propiedad privada en el constructor AnnualSalesChartComponent
. Llame al método que devuelve los datos del gráfico necesarios del servicio dentro del gancho del ciclo de vida ngOnInit
.
// annual-sales-chart.component.ts import { SalesService } from 'src/app/sales/sales.service'; ... export class AnnualSalesChartComponent implements OnInit { public salesChartData: ChartDataSets[] = [ { data: [], label: 'Total Sales' }, ]; public salesChartLabels: Label[] = []; ... constructor(private salesService: SalesService) { } ngOnInit() { this.salesService.getSalesByMonth().subscribe({ next: salesItems => { salesItems.forEach(li => { this.salesChartData[0].data.push(li.revenue); this.salesChartLabels.push(li.month); }); }, ... }); } }
Adición de gráficos al panel
El siguiente paso consiste en agregar los gráficos al tablero, en dash.component.html
. Esto es lo que parece:
<!--dash.component.html--> ... <!--Charts--> <mat-grid-tile [colspan]="( cardLayout | async )?.chart.cols" [rowspan]="( cardLayout | async )?.chart.rows"> <app-card title="Monthly Revenue"> <app-annual-sale-chart></app-annual-sale-chart> </app-card> </mat-grid-tile> <mat-grid-tile [colspan]="( cardLayout | async )?.chart.cols" [rowspan]="( cardLayout | async )?.chart.rows"> <app-card title="Product Sales"> <app-product-sales-chart></app-product-sales-chart> </app-card> </mat-grid-tile> <mat-grid-tile [colspan]="( cardLayout | async )?.chart.cols" [rowspan]="( cardLayout | async )?.chart.rows"> <app-card title="Sales by Traffic Source"> <app-sales-traffic-chart></app-sales-traffic-chart> </app-card> </mat-grid-tile> <mat-grid-tile [colspan]="( cardLayout | async )?.chart.cols" [rowspan]="( cardLayout | async )?.chart.rows"> <app-card title="Online Store Sessions by Traffic Source"> <app-store-sessions-chart></app-store-sessions-chart> </app-card> </mat-grid-tile> ...
Así es como se ve el panel receptivo resultante.
Generando una tabla
Agregaremos una tabla de pedidos para brindarle al propietario de la tienda una descripción general de los pedidos realizados más recientemente y su estado. Para generar el componente de la tabla de pedidos, ejecute el esquema:
ng generate @angular/material:table orders-table
Esto generará un componente de tabla que se verá así.
Es posible que sea difícil hacer que las tablas con muchas columnas respondan a las vistas de dispositivos móviles y tabletas. Al agregar la tabla a una tarjeta, hágala desplazable horizontalmente para que todos los datos se puedan ver correctamente y no se obstruyan. Puede hacer esto agregando el estilo a continuación a su componente de tabla:
<!--table.component.html--> <div class="mat-elevation-z8 small-table"> <table mat-table class="full-width-table" matSort aria-label="Elements"> ...
/*table.component.css*/ ... .small-table{ overflow-x: scroll !important; }
Para agregar la tabla al componente de guión:
<!-- dashboard.component.html> ... <mat-grid-tile [colspan]="( cardLayout | async )?.table.cols" [rowspan]="( cardLayout | async )?.table.rows"> <app-card title="Latest Orders"> <app-orders-table></app-orders-table> </app-card> </mat-grid-tile> ...
Agregar datos a la tabla
Al igual que con los gráficos, puede agregar datos a la tabla en el método ngOnInit
desde un servicio. Además, deberá modificar la fuente de datos generada de su tabla para consumir datos del servicio. Para empezar, inyecte el servicio en el constructor de clases de la tabla. Tomemos el ejemplo de una tabla que enumera los últimos pedidos para este tablero. Para obtener datos para la tabla, OrderService
en el constructor OrdersTableComponent
, cambiemos la aserción de tipo MatTable
del hijo de vista de tabla y modifiquemos la lista de columnas mostradas para reflejar una interfaz de orden. Si está interesado en los datos que se agregan a la tabla, puede encontrarlos aquí. Lo último implica obtener la longitud total de los elementos de datos disponibles para establecer el total en el <mat-paginator>
de la tabla.
// orders-table.component.ts import { OrderService } from '../orders.service'; import { Order } from '../order'; ... export class OrdersTableComponent implements AfterViewInit, OnInit { ... @ViewChild(MatTable) table: MatTable ; dataLength: number; displayedColumns = [ "id", "date", "name", "status", "orderTotal", "paymentMode", ]; ... constructor(private orderService: OrderService){} ngOnInit() { this.datasource = new OrdersTableDataSource(this.orderService); this.orderService.getOrderCount().subscribe({ next: orderCount => { this.dataLength = orderCount; }, ... }); } ... }
// orders-table.component.ts import { OrderService } from '../orders.service'; import { Order } from '../order'; ... export class OrdersTableComponent implements AfterViewInit, OnInit { ... @ViewChild(MatTable) table: MatTable ; dataLength: number; displayedColumns = [ "id", "date", "name", "status", "orderTotal", "paymentMode", ]; ... constructor(private orderService: OrderService){} ngOnInit() { this.datasource = new OrdersTableDataSource(this.orderService); this.orderService.getOrderCount().subscribe({ next: orderCount => { this.dataLength = orderCount; }, ... }); } ... }
A continuación, debemos modificar la clase OrdersTableDataSource
para aceptar OrderService
como parámetro en su constructor. También tendremos que modificar sus métodos de connect
y destroy
. El método de connect
conecta la fuente de datos a la tabla y actualiza la tabla cuando se emiten nuevos elementos de datos desde el flujo que devuelve, en este caso, una matriz de órdenes observable. La constante dataMutations
combina la primera carga de datos, la paginación y los eventos de clasificación en una secuencia para que la tabla los consuma. La paginación y la clasificación están a cargo del lado del servidor de OrderService
. Por lo tanto, debemos pasar el desplazamiento y el tamaño de página del paginador y el campo de clasificación activo y la dirección de clasificación de la propiedad de clasificación al método getOrders
de OrderService
. El método de disconnect
debe usarse para cerrar cualquier conexión realizada y liberar los recursos retenidos en el método de conexión.
// orders-table.datasource.ts ... export class OrdersTableDataSource extends DataSource<Order> { paginator: MatPaginator; sort: MatSort; constructor(private orderService: OrderService) { super(); } connect(): Observable<Order[]> { const dataMutations = [ of('Initial load'), this.paginator.page, this.sort.sortChange ]; return merge(...dataMutations).pipe(mergeMap(() => { return this.orderService.getOrders( this.paginator.pageIndex * this.paginator.pageSize, this.paginator.pageSize, this.sort.active, this.sort.direction ); })); } disconnect() {} }
En la plantilla de la tabla de pedidos, inserte las nuevas columnas y vincule la propiedad de length
de <mat-paginator>
a la propiedad dataLength
. Para la columna de estado, use un elemento <mat-chip>
para una mejor visualización del estado del pedido. Para tener acceso a <mat-chip>
, agregue MatChipsModule
como una importación a AppModule
.
<!-- orders-table.component.html --> <div class="mat-elevation-z8"> <table mat-table class="full-width-table" matSort aria-label="Elements"> <!-- Id Column --> <ng-container matColumnDef="id"> <th mat-header-cell *matHeaderCellDef mat-sort-header>Id</th> <td mat-cell *matCellDef="let row">{{row.id}}</td> </ng-container> <!-- Date Column --> <ng-container matColumnDef="date"> <th mat-header-cell *matHeaderCellDef mat-sort-header>Date</th> <td mat-cell *matCellDef="let row">{{row.date | date }}</td> </ng-container> <!-- Name Column --> <ng-container matColumnDef="name"> <th mat-header-cell *matHeaderCellDef mat-sort-header>Name</th> <td mat-cell *matCellDef="let row">{{row.name}}</td> </ng-container> <!-- Order Total Column --> <ng-container matColumnDef="orderTotal"> <th mat-header-cell *matHeaderCellDef mat-sort-header>Order Total</th> <td mat-cell *matCellDef="let row">{{row.orderTotal | currency}}</td> </ng-container> <!-- Payment Mode Column --> <ng-container matColumnDef="paymentMode"> <th mat-header-cell *matHeaderCellDef mat-sort-header>Payment Mode</th> <td mat-cell *matCellDef="let row">{{row.paymentMode}}</td> </ng-container> <!-- Status Column --> <ng-container matColumnDef="status"> <th mat-header-cell *matHeaderCellDef mat-sort-header>Status</th> <td mat-cell *matCellDef="let row"> <mat-chip-list> <mat-chip color="{{ row.status == 'delivered' ? 'primary' : ( row.status == 'shipped' ? 'accent' : 'warn' ) }}" selected> {{row.status}} </mat-chip> </mat-chip-list> </td> </ng-container> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> </table> <mat-paginator #paginator [length]="dataLength" [pageIndex]="0" [pageSize]="5" [pageSizeOptions]="[5, 10, 15, 20]"> </mat-paginator> </div>
Una vez que se han agregado los datos a la tabla, así es como se verá el tablero:
Creación de un componente de minitarjeta
Todo lo que queda para completar el tablero es llenar las cuatro tarjetas pequeñas que se encuentran en la parte superior. Tener tarjetas de resumen más pequeñas como parte del tablero facilita resaltar breves piezas de información que no necesitan gráficos o tablas completos. En este ejemplo, las cuatro minitarjetas mostrarán las ventas totales, el valor promedio de los pedidos, la cantidad total de pedidos y la cantidad de clientes que regresaron y visitaron la tienda durante el día. Este es solo un ejemplo. Estas minitarjetas no se pueden generar como con la navegación, el diseño del tablero, los gráficos y la tabla. No tienen esquemas. A continuación, veremos brevemente cómo crearlos. Aunque vamos a agregar datos específicos para el ejemplo, puede agregarles lo que quiera o decidir eliminarlos por completo. Para comenzar, genere el componente mini-card
, ejecute:
ng gc mini-card -m app --style css
Puede encontrar la plantilla para el componente vinculado aquí y su estilo aquí. Este componente tiene ocho propiedades de entrada que puede averiguar cómo agregar aquí. Para obtener datos para los componentes de la minitarjeta, inyecte el servicio que les proporciona datos en el constructor DashComponent
. Asigne los datos recibidos del servicio a una propiedad del DashComponent
. En este caso, obtendremos datos de StoreSummaryService
y los asignaremos a la propiedad miniCardData
. Así es cómo:
// dash.component.ts export class DashComponent implements OnInit{ ... miniCardData: StoreSummary[]; constructor(private breakpointObserver: BreakpointObserver, private summaryService: StoreSummaryService) {} ngOnInit() { this.summaryService.getStoreSummary().subscribe({ next: summaryData => { this.miniCardData = summaryData; } }); } }
Para agregar las mini-cards
al componente del tablero y llenarlas con datos del servicio:
<!--dash.component.html--> ... <!--Mini Cards--> <mat-grid-tile *ngFor="let mc of miniCardData" [colspan]="( cardLayout | async )?.miniCard.cols" [rowspan]="( cardLayout | async )?.miniCard.rows"> <app-mini-card [title]="mc.title" [textValue]="mc.textValue" [value]="mc.value" [color]="mc.color" [percentValue]="mc.percentValue"></app-mini-card> </mat-grid-tile> ...
La siguiente captura de pantalla muestra cómo se verá el tablero con las minitarjetas llenas.
Poniendo todo junto
Al final, la plantilla del componente del tablero debe contener:
<!-- dashboard.component.html --> <div class="grid-container"> <h1 class="mat-h1">Dashboard</h1> <mat-grid-list cols="{{ ( cardLayout | async )?.columns }}" rowHeight="200px"> <!--Mini Cards--> <mat-grid-tile *ngFor="let mc of miniCardData" [colspan]="( cardLayout | async )?.miniCard.cols" [rowspan]="( cardLayout | async )?.miniCard.rows"> <app-mini-card [icon]="mc.icon" [title]="mc.title" [value]="mc.value" [color]="mc.color" [isIncrease]="mc.isIncrease" duration="since last month" [percentValue]="mc.percentValue" [isCurrency]="mc. isCurrency"></app-mini-card> </mat-grid-tile> <!--Charts--> <mat-grid-tile [colspan]="( cardLayout | async )?.chart.cols" [rowspan]="( cardLayout | async )?.chart.rows"> <app-card title="Monthly Revenue"> <app-annual-sale-chart></app-annual-sale-chart> </app-card> </mat-grid-tile> <mat-grid-tile [colspan]="( cardLayout | async )?.chart.cols" [rowspan]="( cardLayout | async )?.chart.rows"> <app-card title="Product Sales"> <app-product-sales-chart></app-product-sales-chart> </app-card> </mat-grid-tile> <mat-grid-tile [colspan]="( cardLayout | async )?.chart.cols" [rowspan]="( cardLayout | async )?.chart.rows"> <app-card title="Sales by Traffic Source"> <app-sales-traffic-chart></app-sales-traffic-chart> </app-card> </mat-grid-tile> <mat-grid-tile [colspan]="( cardLayout | async )?.chart.cols" [rowspan]="( cardLayout | async )?.chart.rows"> <app-card title="Online Store Sessions by Traffic Source"> <app-store-sessions-chart></app-store-sessions-chart> </app-card> </mat-grid-tile> <!--Table--> <mat-grid-tile [colspan]="( cardLayout | async )?.table.cols" [rowspan]="( cardLayout | async )?.table.rows"> <app-card title="Latest Orders"> <app-orders-table></app-orders-table> </app-card> </mat-grid-tile> </mat-grid-list> </div>
Esto es lo que contiene el tablero resultante.
Conclusión
La creación de paneles implica una buena cantidad de trabajo y planificación. Una forma de hacer que su construcción sea más rápida es usar los diversos esquemas proporcionados por Angular Material y ng2-charts. Con estos esquemas, la ejecución de un comando generará un componente completamente completo y puede resultar en tener un panel en funcionamiento con bastante rapidez. Esto le deja mucho más tiempo para concentrarse en crear servicios de datos y agregarlos a los componentes de su tablero.
Si desea obtener más información sobre algunos de los esquemas proporcionados por Angular Material, visite material.angular.io, y para los proporcionados por ng2-charts, visite su sitio vinculado aquí.