[英]Get values from Child Component sent to Parent model Angular 9
我創建了一個簡單的表單,作為該表單的一部分,我想使用材料表選擇而不是 select 字段來實現用戶選擇,這樣我就可以在選擇用戶之前看到他們的詳細信息。
我得到了表單和 selectmodel 工作但是我不知道如何將 selectionmodel 數據返回給父 model 並將其綁定到表單控件。 所以希望得到一些幫助
示例代碼:
分配.component.HTML
<form [formGroup]="newAllocationForm">
<mat-horizontal-stepper formArrayName="formArray" linear #stepper>
<mat-step formGroupName="0" [stepControl]="formArray.get([0])">
<ng-template matStepLabel>New Capability Details</ng-template>
<div class="row">
<div class="col">
<mat-form-field class="full-width">
<input matInput placeholder="Vehicle ID" formControlName="vehicleId" required>
<mat-error>
Vehicle Id is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>
</div>
<div>
<button mat-button matStepperNext type="button">Next</button>
</div>
</mat-step>
<mat-step formGroupName="1" [stepControl]="formArray.get([1])">
<ng-template matStepLabel>Select Users</ng-template>
<app-user-table></app-user-table>
<div>
<button mat-button matStepperPrevious type="button">Back</button>
<button mat-button matStepperNext type="button">Next</button>
</div>
</mat-step>
<mat-step>
<ng-template matStepLabel>Done</ng-template>
<p>You are now done.</p>
<div>
<button mat-raised-button color="primary" type="submit" (click)="onSubmit()"
[disabled]="newAllocationForm.invalid">Submit</button>
<button mat-button matStepperPrevious>Back</button>
<button mat-button (click)="stepper.reset()">Reset</button>
</div>
</mat-step>
</mat-horizontal-stepper>
</form>
分配.component.ts
export class CapabilityNewComponent implements OnInit {
newAllocationForm= this.fb.group({
formArray: this.fb.array([
this.fb.group({
vehicleId: ['', Validators.required],
}),
this.fb.group({
users: ['']
})
])
});
constructor(private fb: FormBuilder) { }
ngOnInit(): void {
}
get formArray(): FormArray | null { return this.newAllocationForm.get('formArray') as FormArray; }
onSubmit() {
// get values from child component table and attach to parent form
}
}
用戶表.component.ts
export class UserTableComponent implements OnInit {
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
@ViewChild(MatTable) table: MatTable<UserTableItem>;
dataSource: MatTableDataSource<any>;
selection = new SelectionModel<any>(true, []);
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns = ['select', 'firstName', 'lastName', 'position'];
constructor(public userService: UserService) {
userService.getUsers().subscribe(res => console.log(res));
}
ngOnInit() {
this.userService.getUsers().subscribe(res => {
this.dataSource = new MatTableDataSource(res);
this.dataSource.sort = this.sort;
this.dataSource.paginator = this.paginator;
});
}
applyFilter(event: Event) {
const filterValue = (event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
}
isAllSelected() {
const numSelected = this.selection.selected.length;
const numRows = this.dataSource.data.length;
return numSelected === numRows;
}
masterToggle() {
this.isAllSelected() ?
this.selection.clear() :
this.dataSource.data.forEach(row => this.selection.select(row));
}
}
用戶表.component.html
<div class="mat-elevation-z8">
<table mat-table [dataSource]="dataSource" class="full-width-table" matSort aria-label="Elements">
<ng-container matColumnDef="select">
<th mat-header-cell *matHeaderCellDef>
<mat-checkbox (change)="$event ? masterToggle() : null" [checked]="selection.hasValue() && isAllSelected()"
[indeterminate]="selection.hasValue() && !isAllSelected()">
</mat-checkbox>
</th>
<td mat-cell *matCellDef="let row">
<mat-checkbox (click)="$event.stopPropagation()" (change)="$event ? selection.toggle(row) : null"
[checked]="selection.isSelected(row)">
</mat-checkbox>
</td>
</ng-container>
<ng-container matColumnDef="firstName">
<th mat-header-cell *matHeaderCellDef mat-sort-header>First Name</th>
<td mat-cell *matCellDef="let row">{{row.FirstName}}</td>
</ng-container>
<ng-container matColumnDef="lastName">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Last Name</th>
<td mat-cell *matCellDef="let row">{{row.LastName}}</td>
</ng-container>
<ng-container matColumnDef="position">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Position</th>
<td mat-cell *matCellDef="let row">{{row.Position}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator #paginator [length]="dataSource?.data.length" [pageIndex]="0" [pageSize]="10"
[pageSizeOptions]="[25, 50, 100, 250]">
</mat-paginator>
</div>
如您所見,這主要是取自 Angular Material 網站的標准代碼(沒什么特別的)。 我查看了@Output,但無法理解它如何在這個 model 上工作。
任何意見,將不勝感激。
要將UserTableComponent
的實例用作常規表單控件,您需要它來實現ControlValueAccessor
接口。
我在這里整理了一個 Stackblitz 演示。 要查看 output,請不要使用 Stackblitz 嵌入式開發工具。 使用瀏覽器的本機開發工具。
此接口允許任何自定義 angular 組件成為 angular 表單的一部分。
它由 4 個方法組成:
writeValue(obj: any): void angular 使用此方法在您使用AbstractControl#setValue
時設置組件中的值。
registerOnChange(fn: any): void 由 angular 傳遞給您的組件的方法 ( fn
) 必須在組件的整體值發生變化時調用。 新值必須作為參數傳遞。
registerOnTouched(fn: any): void 方法fn
由 angular 傳遞給您的組件,只要您認為您的組件必須通知 angular 它已被觸摸,就必須調用該方法。
setDisabledState(isDisabled: boolean)?: void 此方法是可選的,只要父組件調用AbstractControl#enable
和AbstractControl#disable
,angular 就會使用該方法
完成以上4項后,你還需要提供你的class作為control value accessor provider。
所以:
@Component({
...
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => UserTableComponent),
multi: true
}]
})
export class UserTableComponent implements ControlValueAccessor, OnInit {
onChange: (any[] | null) => void =
(SelectionModel<any> | null) => {};
onTouched: () => void = () => {};
writeValue(value: SelectionModel<any> | null) {
// set the values of your component
}
registerOnChange(fn: (any | null) => void) {
this.onChange = fn;
}
registerOnTouched(fn: () => void) {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean) {
if(isDisabled) {
// prevent your table to be selected
} else {
// enable your table for being selected
}
}
// whenever the selection changes, you should emit it again
notifyChanges() {
this.onChange(this.selection);
}
}
在您的表組件中,您將擁有:
<mat-checkbox (click)="$event.stopPropagation()"
(change)="_setSelection($event, row)"
[checked]="selection.isSelected(row)">
</mat-checkbox>
在您的 typescript 中:
_setSelection(row: any, change: EventEmitter<MatCheckboxChange>) {
if(change) {
selection.toggle(row);
this.onChange(this.selection.selected);
}
}
這樣做之后你可以這樣做:
<app-user-table formControlName="controlName"></app-user-name>
使用EventEmitter
。 例如,在您的父組件中:
父母.ts
functionThatReceivesDataFromChild($event: YourClass) {
// do stuff with your $event object here.
}
父母.html
<app-child-component (childOutputProperty)="functionThatReceivesDataFromChild($event)"></app-child-component>
在您的子組件中:
子組件.ts
import { ..., Output, EventEmitter } from '@angular/core'
...
@Output() childOutputProperty: EventEmitter<YourClass> = new EventEmitter()
let myFormGroup: FormGroup = ...
formSubmitPressed() {
this.childOutputProperty.emit(this.myFormGroup.value)
}
child.component.html
<form [formGroup]="myFormGroup">
<button (click)="formSubmitPressed()">Submit<button>
</form>
相關文檔在這里: https://angular.io/guide/component-interaction#parent-listens-for-child-event
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.