风一更--软件开发--UI--Angular material-- DragDropList + table
目的: 记录 Angular material dragDrop list + table 组合使用
场景:
<!-- Toolbar--> <header> <nav> <mat-toolbar color="primary"> <button mat-icon-button class="app-icon" aria-label="app icon-button with menu icon"> <mat-icon>menu</mat-icon> </button> <span>Data process & analysis platform</span> <span class="app-spacer"></span> <button mat-icon-button class="app-icon home-icon" aria-label="app icon-button with home icon" routerLink=""> <mat-icon aria-hidden="false" aria-label="app home icon" fontIcon="home">Home</mat-icon> </button> <button mat-icon-button class="app-icon" aria-label="app icon-button with share icon"> <mat-icon>share</mat-icon> </button> </mat-toolbar> </nav> </header> <ng-template cdk-portal #overlayConfig="cdkPortal"> <mat-spinner color="accent"></mat-spinner> </ng-template> <!-- main --> <main class="wrapper"> <mat-toolbar> <mat-slide-toggle [(ngModel)]="configDefault"> configuration default: {{configDefault}} </mat-slide-toggle> <span class="app-spacer"></span> <button class="btn_config_op" mat-stroked-button color="warn" (click)="reset()"> Reset </button> <button class="btn_config_op" mat-stroked-button color="primary" (click)="submitConfig()" [disabled]="overlayRefConfig"> Submit </button> </mat-toolbar> <section class="subcategory"> <mat-sidenav-container [hasBackdrop]="true"> <mat-sidenav disableClose [(opened)]="configDefault"></mat-sidenav> <mat-sidenav-content> <div class="grid-config"> <article class="grid-config-base"> <header><h3>base</h3></header> <mat-table #tb_bases [dataSource]="configInit.bases" class="mat-elevation-z8" cdkDropList id="tb_id_bases" [cdkDropListData]="configInit.bases" [cdkDropListConnectedTo]="['tb_id_conditions','tb_id_comparisons']" (cdkDropListDropped)="dragDropEventHandler($event)"> <ng-container matColumnDef="index"> <mat-header-cell *matHeaderCellDef>no.</mat-header-cell> <mat-cell *matCellDef="let cell;let index = index">{{index + 1}}</mat-cell> </ng-container> <ng-container matColumnDef="partition"> <mat-header-cell *matHeaderCellDef>partition</mat-header-cell> <mat-cell *matCellDef="let cell;let index = index">{{cell.charEntryMeta.partition}}</mat-cell> </ng-container> <ng-container matColumnDef="segment"> <mat-header-cell *matHeaderCellDef>segment</mat-header-cell> <mat-cell *matCellDef="let cell;let index = index">{{cell.charEntryMeta.segment}}</mat-cell> </ng-container> <ng-container matColumnDef="charName"> <mat-header-cell *matHeaderCellDef>char name</mat-header-cell> <mat-cell *matCellDef="let cell;let index = index">{{cell.charEntryMeta.charName}}</mat-cell> </ng-container> <mat-header-row *matHeaderRowDef="metaColumns; sticky: true"></mat-header-row> <mat-row *matRowDef="let row; columns: metaColumns; let index = index" [ngStyle]="{'background': highlight(row)}" cdkDrag [cdkDragData]="row.data" [cdkDragDisabled]="row.assignedCondition && row.assignedCompared"> </mat-row> </mat-table> </article> <article class="grid-config-condition"> <header><h3>condition</h3></header> <mat-table #tb_conditions [dataSource]="configInit.conditions" class="mat-elevation-z8" cdkDropList id="tb_id_conditions" [cdkDropListData]="configInit.conditions" [cdkDropListConnectedTo]="['tb_id_bases']" (cdkDropListDropped)="dragDropEventHandler($event)"> <ng-container matColumnDef="index"> <mat-header-cell *matHeaderCellDef>no.</mat-header-cell> <mat-cell *matCellDef="let cell;let index = index">{{index + 1}}</mat-cell> </ng-container> <ng-container matColumnDef="partition"> <mat-header-cell *matHeaderCellDef>partition</mat-header-cell> <mat-cell *matCellDef="let cell;let index = index">{{cell.charEntryMeta.partition}}</mat-cell> </ng-container> <ng-container matColumnDef="segment"> <mat-header-cell *matHeaderCellDef>segment</mat-header-cell> <mat-cell *matCellDef="let cell;let index = index">{{cell.charEntryMeta.segment}}</mat-cell> </ng-container> <ng-container matColumnDef="charName"> <mat-header-cell *matHeaderCellDef>charName</mat-header-cell> <mat-cell *matCellDef="let cell;let index = index">{{cell.charEntryMeta.charName}}</mat-cell> </ng-container> <ng-container matColumnDef="valueType"> <mat-header-cell *matHeaderCellDef>value type</mat-header-cell> <mat-cell *matCellDef="let cell;let index = index">{{cell.valueType}}</mat-cell> </ng-container> <mat-header-row *matHeaderRowDef="configColumns; sticky: true"></mat-header-row> <mat-row *matRowDef="let row; columns: configColumns;let index = index;" cdkDrag [cdkDragData]="row.data" [cdkDragDisabled]="row.constraint=='MANDATORY'"> </mat-row> </mat-table> </article> <article class="grid-config-comparison"> <header><h3>comparison</h3></header> <mat-table #tb_comparisons [dataSource]="configInit.comparisons" class="mat-elevation-z8" cdkDropList id="tb_id_comparisons" [cdkDropListData]="configInit.comparisons" [cdkDropListConnectedTo]="['tb_id_bases']" (cdkDropListDropped)="dragDropEventHandler($event)"> <ng-container matColumnDef="index"> <mat-header-cell *matHeaderCellDef>no.</mat-header-cell> <mat-cell *matCellDef="let cell;let index = index">{{index + 1}}</mat-cell> </ng-container> <ng-container matColumnDef="partition"> <mat-header-cell *matHeaderCellDef>partition</mat-header-cell> <mat-cell *matCellDef="let cell;let index = index">{{cell.charEntryMeta.partition}}</mat-cell> </ng-container> <ng-container matColumnDef="segment"> <mat-header-cell *matHeaderCellDef>segment</mat-header-cell> <mat-cell *matCellDef="let cell;let index = index">{{cell.charEntryMeta.segment}}</mat-cell> </ng-container> <ng-container matColumnDef="charName"> <mat-header-cell *matHeaderCellDef>char name</mat-header-cell> <mat-cell *matCellDef="let cell;let index = index">{{cell.charEntryMeta.charName}}</mat-cell> </ng-container> <ng-container matColumnDef="valueType"> <mat-header-cell *matHeaderCellDef>value type</mat-header-cell> <mat-cell *matCellDef="let cell"> <mat-select [(ngModel)]="cell.valueType" name="valueType"> <mat-option class="opt_valueType" *ngFor="let val of valueOptions" [value]="val.value"> {{val.viewValue}} </mat-option> </mat-select> </mat-cell> </ng-container> <mat-header-row *matHeaderRowDef="configColumns; sticky: true"></mat-header-row> <mat-row *matRowDef="let row; columns: configColumns; let index = index;" cdkDrag [cdkDragData]="row.data"></mat-row> </mat-table> </article> </div> </mat-sidenav-content> </mat-sidenav-container> </section> </main>
css
h2,h3 { margin: 1px 0 1px; border-bottom: 1px solid #8e3339; } .wrapper { width: 95%; max-width: 100em; margin: 0 auto; } .btn_config_op{ margin: 0 0 0 1.5em; } .subcategory { margin-top: 1.5em; border-bottom: 1px solid #8E3339; } .grid-config { display: -webkit-grid; display: grid; -webkit-grid-template-rows : auto auto auto; grid-template-rows: auto auto auto; -webkit-grid-template-columns: 45% 1fr; grid-template-columns: 45% 1fr; grid-column-gap: .5em; grid-row-gap: .5em; margin: 0 -.375em; } .grid-config-base { -webkit-grid-row: 1/-1; grid-row: 1/-1; -webkit-grid-column: 1; grid-column: 1; padding: .175em; margin: 0 .375em .375em; background-color:skyblue; } .grid-config-condition { -webkit-grid-row: 1; grid-row: 1; -webkit-grid-column: 2; grid-column: 2; padding: .175em; margin: 0 .375em .375em; background-color: red; } .grid-config-comparison{ -webkit-grid-row: 2; grid-row: 2; -webkit-grid-column:2; grid-column: 2; padding: .175em; margin: 0 .375em .375em; background-color: #FFC66D; } /********************************/ .mat-mdc-table{ font-family: "Lucida Sans", Verdana, Arial, sans-serif; border-collapse: collapse; overflow: auto; max-height: 900px; width: 100%; } /*#tb_id_conditions{ font-family: "Lucida Sans", Verdana, Arial, sans-serif; border-collapse: collapse; overflow: auto; height: 900px; width: 100%; }*/ .mat-mdc-table .mat-mdc-row:nth-child(even){ background-color: lightblue; } .mat-mdc-cell { word-break: break-word !important; font-size: xx-small; } .mat-column-index{ border-right: 1px solid currentColor; } /*.mat-column-index{ width: 35px; border-right: 1px solid currentColor; text-align: left; } .mat-column-partition{ width:110px; text-align:left; } .mat-column-segment{ width:150px; text-align:left; } .mat-column-valueType{ width:120px; } .mat-mdc-table .mat-column-charName{ max-width:100% }*/ .mat-mdc-option{ font-size: medium; } .grid-config article header { text-align: center; background-color: wheat; } .grid-config article header h3{ font-style: italic; }
import {Component, OnInit, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core';
import {
ConfigAquaEdgeRegPerform,
ConfigEntryAquaEdgeRegPerform, ConfigEntryMetaAquaEdgeRegPerform
} from "../../model/config_aqua_edge_reg_perform/config_aqua_edge_reg_perform.model";
import {MatTable} from "@angular/material/table";
import {ActivatedRoute, Router} from "@angular/router";
import {ConfigAquaEdgeRegPerformRepository} from "../../model/config_aqua_edge_reg_perform/config_aqua_edge_reg_perform.repository";
import {ConfigAquaEdgeRegPerformRest} from "../../model/config_aqua_edge_reg_perform/config_aqua_edge_reg_perform.rest";
import {CdkOverlayOrigin, Overlay, OverlayConfig, OverlayRef} from "@angular/cdk/overlay";
import {CdkDrag, CdkDragDrop, moveItemInArray, transferArrayItem} from "@angular/cdk/drag-drop";
import {TemplatePortal} from "@angular/cdk/portal";
import {ConfigAquaEdgeRegPerformService} from "../../model/config_aqua_edge_reg_perform/config-aqua-edge-reg-perform.service";
interface valueEnum {
value: string;
viewValue: string;
}
@Component({
selector: 'app-config-aqua-edge-reg-perform',
templateUrl: './config-aqua-edge-reg-perform.component.html',
styleUrls: ['./config-aqua-edge-reg-perform.component.css']
})
export class ConfigAquaEdgeRegPerformComponent implements OnInit {
configDefault: boolean = true;
// @ts-ignore
configInit: ConfigAquaEdgeRegPerform;
// overlay
// @ts-ignore
overlayRefConfig: OverlayRef = null;
// @ts-ignore
@ViewChild("overlayConfig", {static: false}) templatePortal: TemplatePortal;
// table dropList config
metaColumns: string[] = ['index', 'partition', 'segment', 'charName'];
configColumns: string[] = ['index', 'partition', 'segment', 'charName', 'valueType'];
// @ts-ignore
@ViewChild('tb_bases') tb_bases: MatTable<ConfigEntryAquaEdgeRegPerform>;
// @ts-ignore
@ViewChild('tb_conditions') tb_conditions: MatTable<ConfigEntryAquaEdgeRegPerform>;
// @ts-ignore
@ViewChild('tb_comparisons') tb_comparisons: MatTable<ConfigEntryAquaEdgeRegPerform>;
valueOptions: valueEnum[] = [
{value: "STRING", viewValue: "String"},
{value: "NUMBER", viewValue: "Number"}
];
constructor(activatedRoute: ActivatedRoute,
private configService: ConfigAquaEdgeRegPerformService,
private configRest: ConfigAquaEdgeRegPerformRest,
private router: Router,
private overlay: Overlay) {
}
ngOnInit(): void {
this.configInit = this.configService.getInitData();
}
/* init table */
highlight(rowData: ConfigEntryAquaEdgeRegPerform): any {
let conditionAssigned: boolean = rowData.assignedCondition;
let comparisonAssigned: boolean = rowData.assignedCompared;
if (!conditionAssigned && !comparisonAssigned) {
return '';
}
if (conditionAssigned && !comparisonAssigned) {
return 'red';
}
if (!conditionAssigned && comparisonAssigned) {
return '#FFC66D';
}
/* condition and comparison */
return 'lightslategray';
}
/*------------*/
dragDropEventHandler(event: CdkDragDrop<any[]>) {
if (event.previousContainer === event.container) {
moveItemInArray(
event.container.data,
event.previousIndex,
event.currentIndex);
} else {
this.transferHandler(event);
}
this.tb_bases.renderRows();
this.tb_conditions.renderRows();
this.tb_comparisons.renderRows();
}
transferHandler(event: CdkDragDrop<any[]>){
if (event.previousContainer.id === "tb_id_bases") {
this.transferFromBaseToOther(event);
}
if (event.previousContainer.id === "tb_id_conditions") {
this.transferFromOtherToBase(event,true);
}
if (event.previousContainer.id === "tb_id_comparisons") {
this.transferFromOtherToBase(event,false);
}
}
transferFromBaseToOther(event: CdkDragDrop<any[]>) {
let item = event.previousContainer.data[event.previousIndex];
let copiedItem = this.copyMovedItem(item);
if(event.container.id === "tb_id_conditions"){
if(item.assignedCondition){
return;
}
copiedItem.assignedCondition = true;
}
if(event.container.id === "tb_id_comparisons"){
if(item.assignedCompared){
return;
}
copiedItem.assignedCompared = true;
}
transferArrayItem(
event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex);
event.previousContainer.data.splice(
event.previousIndex,0,copiedItem);
}
transferFromOtherToBase(event: CdkDragDrop<any[]>,isFromCondition:boolean) {
let item = event.previousContainer.data[event.previousIndex];
for (let e of event.container.data) {
if(this.isCharEntryMetaEqual(item.charEntryMeta,e.charEntryMeta)){
if(isFromCondition){
e.assignedCondition = false;
}else{
e.assignedCompared = false;
}
break;
}
}
event.previousContainer.data.splice(event.previousIndex, 1);
}
isCharEntryMetaEqual(left: ConfigEntryMetaAquaEdgeRegPerform,
right: ConfigEntryMetaAquaEdgeRegPerform) {
return left.charName == right.charName &&
left.segment == right.segment &&
left.partition == right.partition;
}
dropEntryDuplicatePredicate(item: CdkDrag<any>) {
return false;
}
copyMovedItem(item:any) : ConfigEntryAquaEdgeRegPerform{
return JSON.parse(JSON.stringify(item));
}
//----------------------------------------------------------------------
reset() {
}
submitConfig() {
this.openOverlay();
this.applyConfig();
}
applyConfig() {
let config: ConfigAquaEdgeRegPerform;
if (this.configDefault) {
config = this.buildDefaultConfig();
} else {
config = this.buildCustomizeConfig();
}
// @ts-ignore
this.configRest.postConfig(config).subscribe(res => {
this.handleConfigAppliedRes(res);
});
}
buildDefaultConfig() {
return new ConfigAquaEdgeRegPerform("default", [], [], []);
}
buildCustomizeConfig() {
return new ConfigAquaEdgeRegPerform("customize",
this.configInit.conditions,
[],
this.configInit.comparisons);
}
handleConfigAppliedRes(response: any) {
if (response.statusCode === "NORMAL") {
this.transferToReport(response);
return;
} else {
alert(response.statusCode);
}
}
private transferToReport(response: any) {
const data = {
data: JSON.stringify(response.data)
};
this.router.navigate(["/aqua-edge-regression-performance-report", data]);
}
// overlay
openOverlay() {
const config = new OverlayConfig();
config.positionStrategy = this.overlay.position()
.global().centerVertically().centerHorizontally();
config.disposeOnNavigation = true;
config.hasBackdrop = true;
this.overlayRefConfig = this.overlay.create(config);
this.overlayRefConfig.attach(this.templatePortal);
}
}
export class ConfigEntryAquaEdgeRegPerform{ constructor(public charEntryMeta:ConfigEntryMetaAquaEdgeRegPerform, public sequence:number, public role:string="BASE", public valueType:string = "STRING", public constraint:string = "FREE", public assignedCondition:boolean = false, public assignedCompared : boolean = false) { } } export class ConfigEntryMetaAquaEdgeRegPerform{ constructor(public charName:string, public segment:string, public partition:string){} }

浙公网安备 33010602011771号