簡體   English   中英

從發送給父組件的子組件獲取值 model Angular 9

[英]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 個方法組成:

  1. writeValue(obj: any): void angular 使用此方法在您使用AbstractControl#setValue時設置組件中的值。

  2. registerOnChange(fn: any): void 由 angular 傳遞給您的組件的方法 ( fn ) 必須在組件的整體值發生變化時調用。 新值必須作為參數傳遞。

  3. registerOnTouched(fn: any): void 方法fn由 angular 傳遞給您的組件,只要您認為您的組件必須通知 angular 它已被觸摸,就必須調用該方法。

  4. setDisabledState(isDisabled: boolean)?: void 此方法是可選的,只要父組件調用AbstractControl#enableAbstractControl#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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM