javascript — лучшее решение для связи между компонентом компонента и дочерним компонентом таблицы многократного использования?

Лучшее решение для связи между компонентом компонента и компонентом дочерней таблицы многократного использования?

У меня есть приложение с множеством функций: пользователи, клиенты, продукты, заказы и т. Д. Мне нужно, чтобы пользователь мог выполнять операции CRUD для каждой функции. Таким образом, каждый компонент компонента будет очень похож и должен будет:

  • Таблица для отображения списка функций
  • Кнопка для добавления новой функции.
  • Две кнопки для каждого элемента объекта, отображаемого в таблице, для редактирования или удаления объекта.
  • Таблица фильтра, нумерация страниц и т. Д.

Это пример для функции «usuarios» (пользователи на испанском языке): введите описание изображения здесь

Это изображение практически одинаково для каждой функции. Разница лишь в отображаемых столбцах и названиях некоторых компонентов. Поэтому я решил не дублировать код и создал повторно используемый компонент, который назвал «data-table». Этот общий компонент получает данные от каждой функции, и при нажатии кнопки он отправляет событие компоненту функции. Полезная нагрузка этого события отправляет, какое действие было запущено («создать», «обновить» или «удалить»), и объект, который необходимо обновить или удалить.

Итак, каждый компонент html выглядит так:

 {amp}lt;app-data-table (openDialogEvent)="openDialog($event)" [pageTitle]="pageTitle" [modelName]="modelName" [tableData]="tableData" [columnHeader]="columnHeader"{amp}gt;{amp}lt;/app-data-table{amp}gt; 

Когда компонент компонента получает событие «добавить» или «обновить», он открывает компонент диалоговой формы для этой функции. Каждая функция имеет один из этих компонентов диалоговых форм. Структура файла выглядит следующим образом:

 |-- app |-- feature1 |-- feature1-dialog |-- feature1-dialog.component.html |-- feature1-dialog.component.ts |-- feature1.component.html |-- feature1.component.ts | |-- feature2 |-- feature2-dialog |-- feature2-dialog.component.html |-- feature2-dialog.component.ts |-- feature2.component.html |-- feature2.component.ts | |-- shared |-- data-table |-- data-table.component.html |-- data-table.component.ts 

Проблема у меня заключается в обновлении функции. Допустим, у меня есть функция «заказы».

orders.component.ts

 import { Component, OnInit } from '@angular/core'; import { MatDialog, MatDialogConfig } from '@angular/material'; import { Order } from '../../shared/models/order'; import { OrderService } from '../../services/order.service'; import { OrderDialogComponent } from './order-dialog/order-dialog.component'; import { DialogBoxComponent } from '../../shared/dialog-box/dialog-box.component'; import { DatePipe } from '@angular/common'; @Component({ selector: 'app-orders', templateUrl: './orders.component.html', styleUrls: ['./orders.component.scss'] }) export class OrdersComponent implements OnInit { pageTitle = 'Orders'; modelName = 'order'; columnHeader = { orderNumber: 'Order Number', orderType: 'Order Type', orderDate: 'Order Date', client: 'Client', ... }; tableData: Order[]; constructor(public orderService: OrderService, public dialog: MatDialog, private datePipe: DatePipe) { } ngOnInit() { this.loadOrders(); } loadOrders() { this.orderService.readAll().subscribe((orders: any) ={amp}gt; { this.tableData = orders; }); } openDialog(event) { let dialogRef; const action = event.action; const order = event.obj; const dialogConfig = new MatDialogConfig(); dialogConfig.autoFocus = true; dialogConfig.width = '500px'; if (action === 'Create') { dialogConfig.data = { title: `New order`, action, order }; dialogRef = this.dialog.open(OrderDialogComponent, dialogConfig); dialogRef.afterClosed().subscribe((result) ={amp}gt; { if (result) { this.orderService.create(result).subscribe(() ={amp}gt; this.loadOrders()); } }); } else if (action === 'Update') { dialogConfig.data = { title: `Edit order ${order.orderNumber}`, action, order }; dialogRef = this.dialog.open(OrderDialogComponent, dialogConfig); dialogRef.afterClosed().subscribe((result) ={amp}gt; { if (result) { this.orderService.update(result).subscribe(() ={amp}gt; this.loadOrders()); } }); } else if (action === 'Delete') { dialogConfig.data = { title: `Delete order ${order.orderNumber}`, message: '¿Are you sure?' }; dialogRef = this.dialog.open(DialogBoxComponent, dialogConfig); dialogRef.afterClosed().subscribe((result) ={amp}gt; { if (result) { this.orderService.delete(order._id).subscribe(() ={amp}gt; this.loadOrders()); } }); } } } 

Эта функция связана с другими функциями, такими как «клиенты». Таким образом, в компоненте диалогов диалогов, мне нужно выбрать поле формы, чтобы выбрать из списка клиентов. В этом поле формы хранится только идентификатор выбранного клиента. Вот так выглядит поле формы:

заказ-dialog.comonent.html

 ... {amp}lt;mat-form-field{amp}gt; {amp}lt;mat-label{amp}gt;Client*{amp}lt;/mat-label{amp}gt; {amp}lt;mat-select formControlName="client"{amp}gt; {amp}lt;mat-option *ngFor="let client of clients" [value]="client._id"{amp}gt;{{ client.description }}{amp}lt;/mat-option{amp}gt; {amp}lt;/mat-select{amp}gt; {amp}lt;/mat-form-field{amp}gt; ... 

Когда этот диалог открывается в событии обновления, объект, переданный из компонента orders, должен иметь объект client с полями id и description. Откуда этот объект? Из компонента таблицы данных, когда кнопка щелчка генерирует событие обновления, затем проходит через компонент заказов и переходит непосредственно к компоненту диалога заказов.

Проблема с компонентом таблицы данных. Это многоразово. Он просто отображает данные, которые вы отправляете в массиве с * ngFor для столбцов, которые вы указываете для отображения:

данное table.component.html

 {amp}lt;div class="example-container mat-elevation-z8"{amp}gt; {amp}lt;h1{amp}gt;{{ pageTitle }}{amp}lt;/h1{amp}gt; {amp}lt;div fxLayout="row" fxLayout.xs="column" fxLayoutWrap fxLayoutGap="2.5%" fxLayoutAlign="left"{amp}gt; {amp}lt;div fxLayout="row" fxLayoutAlign="start center"{amp}gt; {amp}lt;button mat-raised-button color="primary" matTooltip="Nuevo {{ modelName }}" (click)="openDialog('Create', {})"{amp}gt; {amp}lt;mat-icon{amp}gt;add{amp}lt;/mat-icon{amp}gt; Nuevo {amp}lt;/button{amp}gt; {amp}lt;/div{amp}gt; {amp}lt;mat-form-field class="example-full-width"{amp}gt; {amp}lt;input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filtrar"{amp}gt; {amp}lt;/mat-form-field{amp}gt; {amp}lt;/div{amp}gt; {amp}lt;div class="table-container mat-elevation-z1"{amp}gt; {amp}lt;table mat-table [dataSource]="dataSource" matSort class="example-full-width"{amp}gt; {amp}lt;!-- Position --{amp}gt; {amp}lt;ng-container matColumnDef="position"{amp}gt; {amp}lt;th mat-header-cell *matHeaderCellDef mat-sort-header{amp}gt;#{amp}lt;/th{amp}gt; {amp}lt;td mat-cell *matCellDef="let element; let i = index"{amp}gt;{{ paginator.pageIndex*paginator.pageSize   i   1 }}{amp}lt;/td{amp}gt; {amp}lt;/ng-container{amp}gt; {amp}lt;!-- Displayed Columns --{amp}gt; {amp}lt;ng-container [matColumnDef]="tableDataKey" *ngFor="let tableDataKey of objectKeys(columnHeader)"{amp}gt; {amp}lt;th mat-header-cell *matHeaderCellDef mat-sort-header{amp}gt; {{ columnHeader[tableDataKey] }} {amp}lt;/th{amp}gt; {amp}lt;td mat-cell *matCellDef="let element"{amp}gt; {{ element[tableDataKey] }}{amp}lt;/td{amp}gt; {amp}lt;/ng-container{amp}gt; {amp}lt;!-- Actions --{amp}gt; {amp}lt;ng-container matColumnDef="actions"{amp}gt; {amp}lt;th mat-header-cell *matHeaderCellDef{amp}gt;Acciones{amp}lt;/th{amp}gt; {amp}lt;td mat-cell *matCellDef="let element" class="action-link"{amp}gt; {amp}lt;button mat-icon-button color="accent" matTooltip="Editar {{ modelName }}" (click)="openDialog('Update', element)"{amp}gt; {amp}lt;mat-icon {amp}gt;edit{amp}lt;/mat-icon{amp}gt; {amp}lt;/button{amp}gt; {amp}lt;button mat-icon-button color="warn" matTooltip="Eliminar {{ modelName }}" (click)="openDialog('Delete', element)"{amp}gt; {amp}lt;mat-icon{amp}gt;delete{amp}lt;/mat-icon{amp}gt; {amp}lt;/button{amp}gt; {amp}lt;/td{amp}gt; {amp}lt;/ng-container{amp}gt; {amp}lt;tr mat-header-row *matHeaderRowDef="displayedColumns"{amp}gt;{amp}lt;/tr{amp}gt; {amp}lt;tr mat-row *matRowDef="let row; columns: displayedColumns;"{amp}gt;{amp}lt;/tr{amp}gt; {amp}lt;/table{amp}gt; {amp}lt;mat-paginator [pageSizeOptions]="[4, 8, 12]" showFirstLastButtons{amp}gt;{amp}lt;/mat-paginator{amp}gt; {amp}lt;/div{amp}gt; {amp}lt;/div{amp}gt; 

данных-table.component.ts

 import { Component, OnInit, ViewChild, Input, SimpleChanges, OnChanges, Output, EventEmitter } from '@angular/core'; import { MatSort, MatTableDataSource, MatDialog, MatTable, MatPaginator } from '@angular/material'; @Component({ selector: 'app-data-table', templateUrl: './data-table.component.html', styleUrls: [ './data-table.component.scss' ] }) export class DataTableComponent implements OnInit, OnChanges { @Input() pageTitle; @Input() modelName; @Input() tableData; @Input() columnHeader; @ViewChild(MatTable, { static: true }) table: MatTable{amp}lt;any{amp}gt;; @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator; @ViewChild(MatSort, { static: true }) sort: MatSort; @Output() openDialogEvent = new EventEmitter{amp}lt;any{amp}gt;(); objectKeys = Object.keys; dataSource; displayedColumns; constructor() {} ngOnInit() {} ngOnChanges(changes: SimpleChanges): void { this.displayedColumns = this.objectKeys(this.columnHeader); this.displayedColumns.unshift('position'); this.displayedColumns.push('actions'); if (changes.tableData) { this.dataSource = new MatTableDataSource(this.tableData); this.dataSource.paginator = this.paginator; this.dataSource.sort = this.sort; } } applyFilter(filterValue: string) { this.dataSource.filter = filterValue.trim().toLowerCase(); } openDialog(action, obj) { this.openDialogEvent.emit({ action, obj }); } } 

Заказы загружаются в компонент заказов и отправляются в компонент таблицы данных, но в таблице отображается [объект] [объект] для поля клиента. Это очевидно, потому что я отправляю только клиентский объект, а не строку. Я только хочу отобразить описание в таблице, но я не могу изменить компонент таблицы данных, чтобы сделать это, потому что он сделан для повторного использования и для других функций. Поэтому мне нужен способ отправить только описание клиента в массиве заказов. Два пути:

1- Вставьте новое поле в массиве orders, т.е. clientDescription и таблицу данных, чтобы отобразить это поле вместо поля client. Это имеет проблему: клиент не единственное поле, у меня есть эта проблема. У меня есть 5 или более полей с этой проблемой. Так что мне нужно было бы добавить 5 или более полей в массив заказов.

2- Дублируйте массив заказов только с данными, которые я хочу отобразить, и в событии обновления возьмите идентификатор обновляемого заказа, отфильтруйте исходный массив заказов с этим идентификатором и отправьте отфильтрованный заказ в компонент диалога заказов , Я думаю, что это может быть слишком сложно и требует дублирования, возможно, большого количества данных.

есть ли другой способ?

Редактировать:

Я нашел полное и очень рекомендуемое решение здесь:

https://medium.com/@ct7/building-a-reusable-table-layout-for-your-angular-2-project-adf6bba3b498

Ключ заключается в том, чтобы создать канал форматирования ячеек, который охватывает все случаи (т. Е. Преобразовывать даты, валюты или даже отображать вложенные значения), и использовать его в таблице многократного использования. Поэтому вы должны передать желаемый формат для каждого поля компоненту таблицы многократного использования … блестяще.

Понравилась статья? Поделиться с друзьями:
JavaScript & TypeScript
Adblock
detector