如何在formArray中正确设置mat-checkbox值,从API读取保存的数据并为新的formArray元素设置默认值(false)?

How to correctly set mat-checkbox values in formArray, reading saved data from API and having default value (false) for new formArray elements?

提问人:laurarana 提问时间:5/24/2023 更新时间:5/24/2023 访问量:19

问:

我正在研究垫子踏步结构,以创建实体“租赁合同”。我可以从零开始创建一个新的租赁合同,或者打开保存的草稿并继续填充数据并将其保存到数据库 usinn 实体框架 API 中。

一份租赁合同可以指客户在合同有效期内使用的n辆车。

每辆车都用一个 formArray 元素表示。每辆车可以由出租房屋拥有,也可以转租,并有许多属性由用户填充。除了复选框之外,几乎所有这些属性都运行良好。

我创建了一个垫子复选框来显示所选机器是否被转租。我需要三种不同的行为:

  1. 当我为 formArray 创建一个空元素时,我需要将“false”值设置为复选框。
  2. 用户选择机器代码后,系统会检查它是否已转租,并将复选框选择设置为“true”(否则为“false”)。
  3. 如果我从草稿加载数据,则需要根据我之前保存在数据库中的内容来设置复选框。

如果我使用 formControl 名称,我将无法管理来自 API 的值。 如果我使用 ngModel,我可以从 DB 中读取,但是当我向其中添加新元素时,formArray 无法正常工作。

我需要的是了解如何配置我的formArray元素,以便开始所有需要的行为。

我的表格如下所示:

在此处输入图像描述

这是我的“混合”代码(我尝试了几次更改并注释了一些不起作用的代码):

component.ts:

[...]
  vehiclesForm = new FormGroup({
    stocks: new FormArray([])
  });

[...]
  ngOnInit(): void {
    this.vehiclesForm = this.formBuilder.group({
      stocks: this.formBuilder.array([])
    });
  }

  loadData(contractData: any) {
    this.contractData = contractData;
    //console.log('contract-vehicles - contractData', contractData);
    this.getAllBuildingSitesByCustomerId(contractData.customerId);
    this.rentalTypeId = contractData.rentalTypeId;
    this.secondRentalTypeId = contractData.secondRentalTypeId;
    //console.log("this.contractData.rentalStocks", this.contractData.rentalStocks);

    if ((<FormArray>this.vehiclesForm.get("stocks")).length === 0) {
      if (this.contractData.rentalStocks != null && this.contractData.rentalStocks?.length > 0) {

        this.getRentalStocksDetail(this.contractData.rentalStocks).subscribe(
          (stockResults) => {
            this.contractData.rentalStocks.forEach((rentalStock, index) => {
              const stock = stockResults[index];
              const stockIdControl = new FormControl(stock, autocompleteObjectValidator());
              this.filteredStocks[index] = stockIdControl.valueChanges.pipe(
                debounceTime(300),
                switchMap((value) => this.getStocks(value, index))
              );
              this.addStockToFormArray(rentalStock, stockIdControl);
              this.onStockSelectionChange(stock, index);
            });
          },
          (err) => {
            console.log("contract-vehicles.component: getRentalStocksDetail:", err);
          },
        );
      } else {
        this.addNewStockToFormArray();
      }
    }
  }

  getRentalStocksDetail(stocks: any[]): Observable<any[]> {
    let calls = [];
    stocks.forEach(stock => { calls.push(this.stockService.getStock(stock.stockId, true)); });
    return forkJoin(calls);
  }

  getControls() {
    //console.log("<FormArray>this.vehiclesForm.get('stocks')).controls",(<FormArray>this.vehiclesForm.get("stocks")).controls);
    return (<FormArray>this.vehiclesForm['controls'].stocks['controls']);
  }

  getStocks(filter: any, index: number): Observable<any[]> {
    if (filter?.length < 2 || typeof filter !== 'string') {
      return of([]);
    }

    this.queryStock.find = filter;
    this.queryStock.startDate = moment(((<FormGroup>(<FormArray>this.vehiclesForm.get("stocks")).controls[index])).controls.startDate.value).format('YYYY-MM-DDT00:00:00');
    this.queryStock.endDate = moment(((<FormGroup>(<FormArray>this.vehiclesForm.get("stocks")).controls[index])).controls.endDate.value).format('YYYY-MM-DDT23:59:59');
    return this.rentalStockService.getAvailableRentalStocks(this.queryStock).pipe(
      map((response) => response),
      tap((response: any[]) => {
        return response.sort((a, b) => {
          if (a.ownerRef === b.ownerRef) {
            return a.registrationNumber < b.registrationNumber ? -1 : 1
          } else {
            return a.ownerRef < b.ownerRef ? -1 : 1
          }
        });
      })
    );
  }

  displayStock(stock: any): string {
    var desc: string;
    if (stock && stock.id) {
      desc = stock.registrationNumber;
      //console.log("stock.ownerRef", stock.ownerRef);
      if (stock.ownerRef) {
        desc = stock.ownerRef + ' - ' + desc;
      }
    }
    return desc;
  }

  addNewStockToFormArray() {
    if (!(<FormArray>this.vehiclesForm.get('stocks')).valid) {
      return;
    }
    const formLength = (<FormArray>this.vehiclesForm.get('stocks')).length;
    const stockIdControl = new FormControl(null, autocompleteObjectValidator());
    this.filteredStocks[formLength] = stockIdControl.valueChanges.pipe(
      debounceTime(300),
      switchMap((value) => this.getStocks(value, formLength))
    );
    this.addStockToFormArray(null, stockIdControl);
  }

  public addStockToFormArray(rentalStock: any, stockControl: FormControl) {
    console.log("rentalStock", rentalStock);
    console.log("subleased", rentalStock?.subleased);
    const checkDefaultValues = <FormGroup>(<FormArray>this.vehiclesForm.get("stocks")).controls[0];
    (<FormArray>this.vehiclesForm.get("stocks")).push(
      new FormGroup({
        stockId: new FormControl(rentalStock ? rentalStock.id : 0),
        startDate: new FormControl(rentalStock?.startDate ?? this.contractData.startDate),
        endDate: new FormControl(rentalStock?.endDate ?? this.contractData.expiryDate),
        stock: stockControl,
        //subleased: new FormControl({value: rentalStock ? rentalStock.subleased : false, disabled: true}),
      })
    );
  }

  onStockSelectionChange(myStock: any, j: number, fromUI: boolean = false) {
    console.log("onStockSelectionChange", fromUI);
    let formArray = (<FormArray>this.vehiclesForm.get("stocks")).controls;
    formArray[j].get('stockId').setValue(myStock.id);
    //formArray[j].get('subleased').setValue(myStock.subleased);
    if (fromUI) {
      this.contractData.rentalStocks[j].subleased = myStock.subleased;
    }
  }

HTML格式:

<form [formGroup]="vehiclesForm">
    <table style="width: 50%;">
        <thead>
            <tr>
                <th style="text-align: center;">{{'StartDate' | translate}}</th>
                <th style="text-align: center;">{{'EndDate' | translate}}</th>
                <th style="text-align: center;">{{'Stock' | translate}}</th>
                <th style="text-align: center;">{{'Subleased' | translate}}</th>
                <th style="text-align: center;">{{'Delete' | translate}}</th>
            </tr>
        </thead>
        <tbody formArrayName="stocks">
            <tr *ngFor="let stock of getControls(); let i = index" [formGroupName]="i">
                <!-- Start Date -->
                <td style="text-align: center;">
                    <div class="hidden">
                        <input type="text" class="form-control" formControlName="stockId">
                    </div>
                    <mat-form-field appearance="outline" class="field-width-120 w-100-p mb-12">
                        <mat-label></mat-label>
                        <input matInput [matDatepicker]="startDatePicker"
                            formControlName="startDate"
                            [min]="contractData.startDate" [max]="contractData.expiryDate">
                        <mat-datepicker-toggle matSuffix [for]="startDatePicker">
                        </mat-datepicker-toggle>
                        <mat-datepicker #startDatePicker></mat-datepicker>
                    </mat-form-field>
                </td>
                <!-- End Date -->
                <td style="text-align: center;">
                    <mat-form-field appearance="outline" class="field-width-120 w-100-p mb-12">
                        <mat-label></mat-label>
                        <input matInput [matDatepicker]="endDatePicker"
                            formControlName="endDate"
                            [min]="contractData.startDate" [max]="contractData.expiryDate">
                        <mat-datepicker-toggle matSuffix [for]="endDatePicker">
                        </mat-datepicker-toggle>
                        <mat-datepicker #endDatePicker></mat-datepicker>
                    </mat-form-field>
                </td>
                <!-- Stock -->
                <td style="text-align: center;">
                    <mat-form-field appearance="outline" class="field-width-stock w-100-p mb-12">
                        <mat-label></mat-label>
                        <input matInput formControlName="stock" [value]="stock"
                            [matAutocomplete]="autoStock" type="text" autocomplete="off">
                        <mat-autocomplete #autoStock="matAutocomplete" [displayWith]="displayStock">
                            <mat-option *ngFor="let myStock of filteredStocks[i] | async"
                                [value]="myStock" (onSelectionChange)="onStockSelectionChange(myStock, i, true)">
                                {{displayStock(myStock)}}
                            </mat-option>
                        </mat-autocomplete>
                    </mat-form-field>
                </td>
                <!-- Subleased -->
                <td style="vertical-align: initial; text-align: center;">
                    <mat-checkbox class="h5" [ngModel]="contractData.rentalStocks[i]?.subleased" [ngModelOptions]="{standalone: true}" disabled></mat-checkbox>
                </td>
                <!-- Delete -->
                <td style="vertical-align: initial; text-align: center;">
                    <button mat-icon-button color="warn"
                        (click)="onDeleteItem(i); $event.preventDefault()">
                        <mat-icon>delete</mat-icon>
                    </button>
                </td>
            </tr>
            <tr>
                <button mat-raised-button class="header-button mt-24 mt-md-0"
                    (click)="addNewStockToFormArray(); $event.preventDefault()">
                    <mat-icon>add</mat-icon>
                </button>
            </tr>
        </tbody>
    </table>
</form>

任何建议/帮助将不胜感激!

非常感谢和最诚挚的问候,

劳 拉

复选框 FormArray Form-Control FormGroups SetValue

评论


答: 暂无答案