angular和ng-zorro 可編輯表格,響應式表單,增加,刪除,編輯一行,並附有校驗功能
效果圖:
table-edit-row.component.html
<form nz-form [formGroup]="validateForm"> <button nz-button nzType="dashed" class="add-button" (click)="addRow()"> <i nz-icon nzType="plus"></i> Add field </button> <button nz-button (click)="submitData()" nzType="primary">提交</button> <br /> <br /> <nz-table [nzShowPagination]="false" nzSize="middle" #editRowTable nzBordered [nzData]="listOfData"> <thead> <tr> <th>Name</th> <th>Mobile</th> <th>Address</th> <th nzWidth="200px">Action</th> </tr> </thead> <tbody> <ng-container formArrayName="aliases"> <tr [formGroupName]="i" *ngFor="let data of aliases.controls;let i=index" class="editable-row"> <ng-container *ngIf="editId != data.value.id; else editTemplate"> <td> {{data.value.name}} </td> <td> {{data.value.mobile}} </td> <td> {{data.value.address}} </td> <td> <a (click)="deleteRow(i)">delete</a> <a (click)="startEdit(data.value)">edit</a> </td> </ng-container> <ng-template #editTemplate> <ng-container> <td> <nz-form-item> <nz-form-control nzSpan="1-24" nzErrorTip="請輸入姓名"> <input type="text" nz-input formControlName="name" maxlength="4" /> </nz-form-control> </nz-form-item> </td> <td> <nz-form-item> <nz-form-control nzSpan="1-24" [nzErrorTip]="errorTpl"> <input type="text" nz-input formControlName="mobile" /> <ng-template #errorTpl let-control> <ng-container *ngIf="control.hasError('required')">請輸入電話</ng-container> <ng-container *ngIf="control.hasError('confirm')"> 請輸入正確格式的電話號碼 </ng-container> </ng-template> </nz-form-control> </nz-form-item> </td> <td> <nz-form-item> <nz-form-control nzSpan="1-24" nzErrorTip="請輸入地址"> <input type="text" nz-input formControlName="address" /> </nz-form-control> </nz-form-item> </td> <td> <a (click)="deleteRow(i)">delete</a> <a nzType="link" (click)="saveRow()">save</a> <!-- <a (click)="stopEdit(data.value)">cancel</a> --> </td> </ng-container> </ng-template> </tr> </ng-container> </tbody> </nz-table> <nz-pagination [nzPageSize]="10" [(nzPageIndex)]="current" [nzTotal]="listOfData.length"></nz-pagination> </form>
table-edit-row.component.ts
import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormControl, FormGroup, FormArray, Validators } from '@angular/forms'; import { NzMessageService } from 'ng-zorro-antd/message'; interface ItemData { id: string; name: string; mobile: string; address: string; } @Component({ selector: 'app-table-edit-row', templateUrl: './table-edit-row.component.html', styleUrls: ['./table-edit-row.component.css'] }) export class TableEditRowComponent implements OnInit { validateForm!: FormGroup; current:number = 1; i = 0; rowData: object = {}; editId: string | null = null; listOfData: ItemData[] = [{ id: '001', name: '小明1', mobile: '13120257131', address: '上海', }, { id: '002', name: '小明2', mobile: '13120257132', address: '北京', },{ id: '003', name: '小明3', mobile: '13120257131', address: '廣州', }]; startEdit(rowData: any): void { for (const i in this.validateForm.controls) { if (this.validateForm.controls.hasOwnProperty(i)) { this.validateForm.controls[i].markAsDirty(); this.validateForm.controls[i].updateValueAndValidity(); } } if (!this.validateForm.valid) { this.message.create('error', '只能同時編輯一行') } else { this.rowData = rowData; this.editId = rowData.id; } } stopEdit(row: any): void { //取消 有bug 暫時先不顯示 for (let index = 0; index < this.validateForm.value.aliases.length; index++) { const element = this.validateForm.value.aliases[index]; if (element.id == row.id) { this.validateForm.value.aliases[index] = this.rowData; console.log('this.validateForm.value.aliases', this.validateForm.value.aliases) } } let tempList = this.validateForm.value.aliases; this.validateForm.patchValue({ aliases: tempList }) this.editId = null; } addRow(): void { let allowAdd = false; for (let index = 0; index < this.validateForm.value.aliases.length; index++) { const element = this.validateForm.value.aliases[index]; if (element.name && element.mobile && element.address) { allowAdd = true; } else { allowAdd = false; } } if (allowAdd) { // if (this.validateForm.valid) { let editId = JSON.stringify(Date.now()); this.aliases.push(this.fb.group({ id: editId, name: ['', [Validators.required]], mobile: ['', [Validators.required, this.confirmationValidator]], address: ['', [Validators.required]], })) this.editId = editId; } else { this.message.create('error', '只能新增一行') } } saveRow() { // this.editId = null; if (this.validateForm.valid) { this.editId = null; console.log('value', this.validateForm.value.aliases) } else { this.message.create('error', '請完善此行信息') } } submitData() { for (const i in this.validateForm.controls) { if (this.validateForm.controls.hasOwnProperty(i)) { this.validateForm.controls[i].markAsDirty(); this.validateForm.controls[i].updateValueAndValidity(); } } if (!this.validateForm.valid) { this.message.create('error', '請補全信息') } if (this.validateForm.valid) { console.log('submit:', this.validateForm.value.aliases) } } deleteRow(index: any): void { // console.log(index); this.removeFormArrayItem(index); console.log('this.validateForm.value.aliases', this.validateForm.value.aliases) // this.listOfData = this.listOfData.filter(d => d.id !== id); } get aliases() { return this.validateForm.get('aliases') as FormArray; } //刪除表單組 removeFormArrayItem(index: any) { this.aliases.removeAt(index); } // 生成唯一值 getUID() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { const r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } confirmationValidator = (control: FormControl): { [s: string]: boolean } => { if (!control.value) { return { required: true }; } else if (!(/^1[3456789]\d{9}$/.test(control.value))) { return { confirm: true, error: true }; } return {}; }; constructor( private fb: FormBuilder, private message: NzMessageService ) { } ngOnInit(): void { this.validateForm = this.fb.group({ aliases: this.fb.array([]) }) for (let index = 0; index < this.listOfData.length; index++) { const element = this.listOfData[index]; this.aliases.push(this.fb.group({ id: element.id, name: [element.name, [Validators.required]], mobile: [element.mobile, [Validators.required, this.confirmationValidator]], address: [element.address, [Validators.required]], })) } // console.log(this.validateForm) console.log(this.aliases.controls) } }