如何为angular 5中的Angular材料数据表创建可重用组件 [英] How to create reusable component for Angular material data table in angular 5

查看:22
本文介绍了如何为angular 5中的Angular材料数据表创建可重用组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有几个组件以表格形式显示数据.我想将代码重构为可重用的数据表组件,以便其他组件可以使用它,而不是在每个组件中复制表格.但我不确定如何创建可重用的 Angular 材料数据表.任何人都可以帮我解决这个问题.

<mat-table #table [dataSource]="dataSource" matSort matSortActive="locationName" matSortDirection="asc" matSortDisableClear><ng-container matColumnDef="locationName"><mat-h​​eader-cell *matHeaderCellDef mat-sort-header>位置名称 </mat-h​​eader-cell><mat-cell *matCellDef="let location">{{location.locationName}} </ng-容器><ng-container matColumnDef="address"><mat-h​​eader-cell *matHeaderCellDef>地址</mat-h​​eader-cell><mat-cell *matCellDef="let location">{{location.address}} </mat-cell></ng-容器><ng-container matColumnDef="city"><mat-h​​eader-cell *matHeaderCellDef mat-sort-header>城市</mat-h​​eader-cell><mat-cell *matCellDef="let location">{{location.city}} </mat-cell></ng-容器><ng-container matColumnDef="country"><mat-h​​eader-cell *matHeaderCellDef mat-sort-header>国家</mat-h​​eader-cell><mat-cell *matCellDef="let location">{{location.country}} </mat-cell></ng-容器><ng-container matColumnDef="zipcode"><mat-h​​eader-cell *matHeaderCellDef>邮政编码 </mat-h​​eader-cell><mat-cell *matCellDef="let location">{{location.zipcode}} </mat-cell></ng-容器><ng-container matColumnDef="电话"><mat-h​​eader-cell *matHeaderCellDef>电话 </mat-h​​eader-cell><mat-cell *matCellDef="let location">{{location.phone}} </mat-cell></ng-容器><ng-container matColumnDef="timezone"><mat-h​​eader-cell *matHeaderCellDef>时区</mat-h​​eader-cell><mat-cell *matCellDef="let location">{{location.timezone}} </mat-cell></ng-容器><ng-container matColumnDef="action"><mat-h​​eader-cell *matHeaderCellDef>动作</mat-h​​eader-cell><mat-cell *matCellDef="let location"><a [routerLink]="['/admin/location/edit/',location.locationID]" class="btn Action-Tab">Edit</a>&nbsp;&nbsp;<a class="btn Action-Tab" (click)="deleteLocation(location,location.locationID)">Delete</a></mat-cell></ng-容器><mat-h​​eader-row *matHeaderRowDef="displayedColumns"></mat-h​​eader-row><mat-row *matRowDef="let location; 列:displayColumns;"></mat-row></mat-table><mat-paginator [pageSizeOptions]="[10, 20, 50,100]"></mat-paginator>

解决方案

您可以使用接口和抽象类、泛型并与列共享 .html 文件.这是我用角度@angular/core":4.2.4"的一个小例子,我用它来显示数据:

文件:shared-bce-read-table.interface.ts

import {BehaviorSubject} from 'rxjs/BehaviorSubject';从'../../entities/common/product-table-editable/footer-identifiable-total-quantity.interface'导入{FooterIdentifiableTotalQuantityInterface};/*** 共享接口读取数据*/导出接口 SharedBceReadTableInterface{显示列:字符串[];displayColumnsFooter: string[];dataChange: BehaviorSubject;数据():T[];数据源:SharedBceReadDataSource}

我使用接口来标识通用 T.

文件:footer-identifiable-total-quantity.interface.ts

/*** 在编辑表中管理总量总和的接口.*/导出接口 FooterIdentifiableTotalQuantityInterface {isFooterRow:布尔值;getBalance():数字;getAmountBalance(): 数字;}

现在是通用数据源.

文件:shared-bce-read-data-source.component.ts

从'@angular/material'导入{MatPaginator, MatSort};从 'rxjs/Observable' 导入 {Observable};从@angular/cdk/collections"导入{DataSource};从'./shared-bce-read-table.interface'导入{SharedBceReadTableInterface};从'../../entities/common/product-table-editable/footer-identifiable-total-quantity.interface'导入{FooterIdentifiableTotalQuantityInterface};/*** SharedRead,对于这个辅助组件,排序器的元素必须等于标识符列表.*/导出类 SharedBceReadDataSource扩展数据源{构造函数(私有_table:SharedBceReadTableInterface<T>,私有_sort:MatSort,私有_paginator:MatPaginator){极好的();}connect(): Observable{const displayDataChanges = [this._table.dataChange,this._sort.sortChange,this._paginator.page];return Observable.merge(...displayDataChanges).map(() => {const data = this.getSortedData();const startIndex = this._paginator.pageIndex * this._paginator.pageSize;返回 data.splice(startIndex, this._paginator.pageSize);});}断开连接(){}getSortedData(): T[] {const data = this._table.data().slice();if (!this._sort.active || this._sort.direction === '') { 返回数据;}返回 data.sort((a, b) => {const propertyA: number|string = a[this._sort.active];const propertyB: number|string = b[this._sort.active];const valueA = isNaN(+propertyA) ?属性A:+属性A;const valueB = isNaN(+propertyB) ?属性B:+属性B;return (valueA < valueB ? -1 : 1) * (this._sort.direction === 'asc' ? 1 : -1);});}}

现在我们可以在我们希望显示数据的每个组件中实现这些类.

import {Component, Inject, OnInit, ViewChild} from '@angular/core';从@angular/material"导入{MAT_DIALOG_DATA、MatDialogRef、MatPaginator、MatSort};从'ng-jhipster'导入{JhiAlertService,JhiEventManager};从'../../../core/loading-overlay/loading-overlay.service'导入{LoadingOverlayService};进口 {DEFAULT_ID_SORT,每页项目,PAGE_SIZE_OPTIONS,响应包装器,SharedBceReadDataSource,SharedBceReadTableInterface,首页}来自'../../../shared';从'../../product-order/product-order-bce.model'导入{ProductOrderBce};从 'rxjs/BehaviorSubject' 导入 {BehaviorSubject};从'../../product-order'导入{ProductOrderBceService};@成分({选择器:'jhi-order-detail-product-purchase-order',templateUrl: '订单详细信息-产品-采购订单.html'})导出类 OrderDetailProductPurchaseOrderComponent 实现 OnInit、SharedBceReadTableInterface{displayColumns = ['purchaseOrderFolio', 'productKey', 'description', 'unitMeasureKey', 'quantity', 'unitPrice', 'amount'];displayColumnsFooter = [];dataChange: BehaviorSubject= new BehaviorSubject([]);当局:任何[];数据源:SharedBceReadDataSource= 空;pageSizeOptions = PAGE_SIZE_OPTIONS;itemsPerPage = ITEMS_PER_PAGE;总金额 = 0;总数量 = 0;@ViewChild(MatSort) sortComponent: MatSort;@ViewChild(MatPaginator) paginatorComponent: MatPaginator;构造函数(private dialogRef: MatDialogRef,@Inject(MAT_DIALOG_DATA) 公共数据对话框:任何,私人服务:ProductOrderBceService,私人事件管理器:JhiEventManager,私人警报服务:JhiAlertService,受保护的 loadingService:LoadingOverlayService) {}ngOnInit() {this.authorities = ['ROLE_USER', 'ROLE_ADMIN'];this.dataChange.subscribe((data) => {data.forEach((row) => {this.totalQuantity += row.quantity;this.totalAmount += row.amount;});}, (错误) =>{this.totalAmount = 0;this.totalQuantity = 0;});this.dataSource = new SharedBceReadDataSource(this, this.sortComponent, this.paginatorComponent);this.loadingService.startLoading();this.service.searchByOrigenOrder({page: START_PAGE, size: ITEMS_PER_PAGE, sort: DEFAULT_ID_SORT,orderId: this.dataDialog.orderId, orderVersion: this.dataDialog.orderVersion, productId: this.dataDialog.productId}).subscribe((res: ResponseWrapper) =>{this.dataChange.next(res.json.items);this.loadingService.stopLoading();},(res: ResponseWrapper) =>{this.dataChange.next([]);this.onError(res.json());this.loadingService.stopLoading();});}onError(错误){this.alertService.error(error.message, null, null);}onCloseCancel() {this.dialogRef.close();}公共数据():ProductOrderBce[] {返回 this.dataChange.value;}}

产品订单必须实现 FooterIdentifiableTotalQuantityInterface 接口才能与表格兼容.

product-order-bce.model.ts

import { BaseEntity } from './../../shared';从@angular/core"导入{EventEmitter};导入 {IdentifiableProductI, ProductEditableI} from '../common';从'../common/product-table-editable/footer-identifiable-total-quantity.interface'导入{FooterIdentifiableTotalQuantityInterface};导出类 ProductOrderBce 实现 BaseEntity、IdentifiableProductI、FooterIdentifiableTotalQuantityInterface {id:数字=空;isFooterRow = false;构造函数(身份证号码,公开数量?:数量,公共余额?:数字,公共单价?:数字,公开金额?:数字,public amountBalance?: number,public totalRecivedQuantity?: number,公共产品 ID?:数字,public unitMeasureId?: number,公共产品OrderId?:编号,公共产品OrderVersion?: number,公共产品OrderFolio?:字符串,公共产品描述?:字符串,public unitMeasureDescription?: 字符串,public unitMeasureKey?: 字符串,公共产品密钥?:字符串,public origenProductOrderId?: number,public origenProductOrderQuantity?: number,public origenProductOrderReceivedQuantity?: number){this.quantity = 0;this.unitPrice = 0;this.amount = 0;this.totalRecivedQuantity = 0;this.id = id;}getId(): 任何 {返回 this.id;}getProductKey(): 字符串 {返回 this.productKey;}getProductDescription(): 字符串 {返回 this.productDescription;}获取余额(){返回 this.quantity - this.totalRecivedQuantity;}getAmountBalance() {返回 this.getBalance() * this.unitPrice;}}

如果您观察显示它所实现的表格的逻辑,您只需包含每个案例的文件.html,完成显示的Columns,我这里用的是material-angular.我希望这可以帮助你,同样的事情发生在我身上,我用这些类来显示任何对象的详细视图.

I have couple of components which displays data in table form . I want to refactor the code into reusable data table component so that other components can use it instead of duplicating the table in every component.But I am not sure how to create a reusable Angular material data table. Can anyone pls help me with this.

<div class="example-container" #TABLE> 

  <mat-table #table [dataSource]="dataSource" matSort matSortActive="locationName" matSortDirection="asc" matSortDisableClear>
    <ng-container matColumnDef="locationName">
      <mat-header-cell *matHeaderCellDef mat-sort-header>Location Name </mat-header-cell>
      <mat-cell *matCellDef="let location"> {{location.locationName}} </mat-cell>
    </ng-container>
    <ng-container matColumnDef="address">
      <mat-header-cell *matHeaderCellDef>Address </mat-header-cell>
      <mat-cell *matCellDef="let location"> {{location.address}} </mat-cell>
    </ng-container>
    <ng-container matColumnDef="city">
      <mat-header-cell *matHeaderCellDef mat-sort-header> City </mat-header-cell>
      <mat-cell *matCellDef="let location"> {{location.city}} </mat-cell>
    </ng-container>
    <ng-container matColumnDef="country">
      <mat-header-cell *matHeaderCellDef mat-sort-header>Country </mat-header-cell>
      <mat-cell *matCellDef="let location"> {{location.country}} </mat-cell>
    </ng-container>
    <ng-container matColumnDef="zipcode">
      <mat-header-cell *matHeaderCellDef>ZipCode </mat-header-cell>
      <mat-cell *matCellDef="let location"> {{location.zipcode}} </mat-cell>
    </ng-container>
    <ng-container matColumnDef="phone">
      <mat-header-cell *matHeaderCellDef>Phone </mat-header-cell>
      <mat-cell *matCellDef="let location"> {{location.phone}} </mat-cell>
    </ng-container>
    <ng-container matColumnDef="timezone">
      <mat-header-cell *matHeaderCellDef> TimeZone </mat-header-cell>
      <mat-cell *matCellDef="let location"> {{location.timezone}} </mat-cell>
    </ng-container>
    <ng-container matColumnDef="action">
      <mat-header-cell *matHeaderCellDef> Action </mat-header-cell>
      <mat-cell *matCellDef="let location">
      <a [routerLink]="['/admin/location/edit/',location.locationID]" class="btn Action-Tab">Edit</a>&nbsp;&nbsp;
      <a class="btn Action-Tab" (click)="deleteLocation(location,location.locationID)">Delete</a>
        </mat-cell>
    </ng-container>
    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
    <mat-row *matRowDef="let location; columns: displayedColumns;">
    </mat-row>
  </mat-table>

  <mat-paginator [pageSizeOptions]="[10, 20, 50,100]"></mat-paginator>

解决方案

You can use interfaces and abstract classes, generics and share the .html file with the columns. This is a small example that I used with angle "@ angular / core": "4.2.4", I used it to display data:

File: shared-bce-read-table.interface.ts

import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import {FooterIdentifiableTotalQuantityInterface} from '../../entities/common/product-table-editable/footer-identifiable-total-quantity.interface';

/**
 * Shared interface to read data
 */
export interface SharedBceReadTableInterface<T extends FooterIdentifiableTotalQuantityInterface>{

    displayedColumns: string[];
    displayedColumnsFooter: string[];
    dataChange: BehaviorSubject<T[]>;
    data(): T[];
    dataSource: SharedBceReadDataSource<T>
}

I use an interface to identify the generic T.

File: footer-identifiable-total-quantity.interface.ts

/**
 * Interface to management total quantity sum in editing tables.
 */
export interface FooterIdentifiableTotalQuantityInterface {

    isFooterRow: boolean;

    getBalance(): number;

    getAmountBalance(): number;
}

Now a generic datasource.

File: shared-bce-read-data-source.component.ts

import {MatPaginator, MatSort} from '@angular/material';
import {Observable} from 'rxjs/Observable';
import {DataSource} from '@angular/cdk/collections';
import {SharedBceReadTableInterface} from './shared-bce-read-table.interface';
import {FooterIdentifiableTotalQuantityInterface} from '../../entities/common/product-table-editable/footer-identifiable-total-quantity.interface';

/**
 * SharedRead, for this auxiliary component, of elements for sorter must be equals to identifier columns table.
 */
export class SharedBceReadDataSource<T extends FooterIdentifiableTotalQuantityInterface> extends DataSource<T> {
    constructor(private _table: SharedBceReadTableInterface<T>, private _sort: MatSort, private _paginator: MatPaginator) {
        super();
    }

    connect(): Observable<T[]> {
        const displayDataChanges = [
            this._table.dataChange,
            this._sort.sortChange,
            this._paginator.page
        ];

        return Observable.merge(...displayDataChanges).map(() => {
            const data = this.getSortedData();

            const startIndex = this._paginator.pageIndex * this._paginator.pageSize;
            return data.splice(startIndex, this._paginator.pageSize);
        });
    }

    disconnect() {}

    getSortedData(): T[] {
        const data = this._table.data().slice();
        if (!this._sort.active || this._sort.direction === '') { return data; }

        return data.sort((a, b) => {
            const propertyA: number|string = a[this._sort.active];
            const propertyB: number|string = b[this._sort.active];

            const valueA = isNaN(+propertyA) ? propertyA : +propertyA;
            const valueB = isNaN(+propertyB) ? propertyB : +propertyB;

            return (valueA < valueB ? -1 : 1) * (this._sort.direction === 'asc' ? 1 : -1);
        });
    }
}

Now we can implement these classes every component where we expect to display data.

import {Component, Inject, OnInit, ViewChild} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialogRef, MatPaginator, MatSort} from '@angular/material';
import {JhiAlertService, JhiEventManager} from 'ng-jhipster';
import {LoadingOverlayService} from '../../../core/loading-overlay/loading-overlay.service';
import {
    DEFAULT_ID_SORT,
    ITEMS_PER_PAGE,
    PAGE_SIZE_OPTIONS,
    ResponseWrapper,
    SharedBceReadDataSource,
    SharedBceReadTableInterface,
    START_PAGE
} from '../../../shared';
import {ProductOrderBce} from '../../product-order/product-order-bce.model';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import {ProductOrderBceService} from '../../product-order';

@Component({
    selector: 'jhi-order-detail-product-purchase-order',
    templateUrl: 'order-detail-product-purchase-order.html'
})
export class OrderDetailProductPurchaseOrderComponent implements OnInit, SharedBceReadTableInterface<ProductOrderBce> {

    displayedColumns = ['purchaseOrderFolio', 'productKey', 'description', 'unitMeasureKey', 'quantity', 'unitPrice', 'amount'];
    displayedColumnsFooter = [];
    dataChange: BehaviorSubject<ProductOrderBce[]> = new BehaviorSubject<ProductOrderBce[]>([]);
    authorities: any[];
    dataSource: SharedBceReadDataSource<ProductOrderBce> = null;
    pageSizeOptions = PAGE_SIZE_OPTIONS;
    itemsPerPage = ITEMS_PER_PAGE;
    totalAmount = 0;
    totalQuantity = 0;

    @ViewChild(MatSort) sortComponent: MatSort;
    @ViewChild(MatPaginator) paginatorComponent: MatPaginator;

    constructor(
        private dialogRef: MatDialogRef<OrderDetailProductPurchaseOrderComponent>,
        @Inject(MAT_DIALOG_DATA) public dataDialog: any,
        private service: ProductOrderBceService,
        private eventManager: JhiEventManager,
        private alertService: JhiAlertService,
        protected loadingService: LoadingOverlayService
    ) {}

    ngOnInit() {
        this.authorities = ['ROLE_USER', 'ROLE_ADMIN'];
        this.dataChange.subscribe((data) => {
            data.forEach((row) => {
                this.totalQuantity += row.quantity;
                this.totalAmount += row.amount;
            });
        }, (error) => {
            this.totalAmount = 0;
            this.totalQuantity = 0;
        });
        this.dataSource = new SharedBceReadDataSource<ProductOrderBce>(this, this.sortComponent, this.paginatorComponent);
        this.loadingService.startLoading();
        this.service.searchByOrigenOrder({page: START_PAGE, size: ITEMS_PER_PAGE, sort: DEFAULT_ID_SORT,
            orderId: this.dataDialog.orderId, orderVersion: this.dataDialog.orderVersion, productId: this.dataDialog.productId}).subscribe(
            (res: ResponseWrapper) => {
                this.dataChange.next(res.json.items);
                this.loadingService.stopLoading();
            },
            (res: ResponseWrapper) => {
                this.dataChange.next([]);
                this.onError(res.json());
                this.loadingService.stopLoading();
            }
        );
    }

    onError(error) {
        this.alertService.error(error.message, null, null);
    }

    onCloseCancel() {
        this.dialogRef.close();
    }

    public data(): ProductOrderBce[] {
        return this.dataChange.value;
    }

}

Product order must implement the FooterIdentifiableTotalQuantityInterface interface to be compatible with the table.

product-order-bce.model.ts

import { BaseEntity } from './../../shared';
import {EventEmitter} from '@angular/core';
import {IdentifiableProductI, ProductEditableI} from '../common';
import {FooterIdentifiableTotalQuantityInterface} from '../common/product-table-editable/footer-identifiable-total-quantity.interface';

export class ProductOrderBce implements BaseEntity, IdentifiableProductI, FooterIdentifiableTotalQuantityInterface {
    id: number = null;
    isFooterRow = false;

    constructor(
        id?: number,
        public quantity?: number,
        public balance?: number,
        public unitPrice?: number,
        public amount?: number,
        public amountBalance?: number,
        public totalRecivedQuantity?: number,
        public productId?: number,
        public unitMeasureId?: number,
        public productsOrderId?: number,
        public productsOrderVersion?: number,
        public productsOrderFolio?: string,
        public productDescription?: string,
        public unitMeasureDescription?: string,
        public unitMeasureKey?: string,
        public productKey?: string,
        public origenProductOrderId?: number,
        public origenProductOrderQuantity?: number,
        public origenProductOrderReceivedQuantity?: number
    ) {
        this.quantity = 0;
        this.unitPrice = 0;
        this.amount = 0;
        this.totalRecivedQuantity = 0;
        this.id = id;
    }

    getId(): any {
        return this.id;
    }

    getProductKey(): string {
        return this.productKey;
    }

    getProductDescription(): string {
        return this.productDescription;
    }

    getBalance() {
        return this.quantity - this.totalRecivedQuantity;
    }

    getAmountBalance() {
        return this.getBalance() * this.unitPrice;
    }

}

If you observe the logic of displaying the table it is implemented, you would only have to include the file for each case. html, complete the displayed Columns, I used material-angular here. I hope and this can help you, the same thing happened to me and these classes I use to show detailed views of any object.

这篇关于如何为angular 5中的Angular材料数据表创建可重用组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆