具有基于信号的服务的 Angular Reactive Form

问题描述 投票:0回答:1

我有一个实体

CarrierFilterOption
:

export interface CarrierFilterOption {
    label: string;
    isChecked: boolean;    
}

反应形式定义为:

  plansService = inject(PlansService);
  
  planListForm = this.formBuilder.group({
    carrierFilterOptions: this.formBuilder.array<CarrierFilterOption>([])
  });

我需要使用通过 HTTP API 调用从plansService 加载并表示为信号的值来填充

carrierFilterOptions 

@Injectable({ providedIn: 'root' })
export class PlansService {
    public filterOptions = signal<CarrierFilterOption[]>([]);
    
    constructor() { 
        // filterOptions are populated from HTTP call to API
    }
}

当我使用类似的东西时

this.planListForm.controls.carrierFilterOptions.setValue(this.plansService.filterOptions());

ngOnInit 
我正在

ERROR Error: NG01000: 
    There are no form controls registered with this array yet. If you're using ngModel,
    you may want to check next tick (e.g. use setTimeout).

如何最好地做到这一点?或者信号对于这种情况来说不是一个好主意?

angular signals angular-reactive-forms
1个回答
0
投票

由于您尚未共享正在使用的数据对象,因此我们需要订阅组件上的数据,因为表单值将在获取表单数据后立即设置,这是遗漏的部分,我们需要循环遍历数据并为每一行创建

FormGroup/FormControl
并将其推送到
FormArray
(CarrierFilterOptions)
,然后最后为每个控件运行
*ngFor
并将它们呈现在表单上!由于我没有数据,我创建了一个模拟形式,希望它能帮助您!

ts

import { CommonModule } from '@angular/common';
import { Component, inject } from '@angular/core';
import {
  FormArray,
  FormBuilder,
  FormControl,
  FormGroup,
  ReactiveFormsModule,
} from '@angular/forms';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
import { PlansService } from './plans.service';

export interface CarrierFilterOption {
  label: string;
  isChecked: boolean;
}

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [ReactiveFormsModule, CommonModule],
  template: `
    <form [formGroup]="planListForm">
      <div formArrayName="carrierFilterOptions">
        <ng-container *ngFor="let control of carrierFilterOptions.controls; let i = index">
          <div [formGroupName]="i" *ngIf="filterOptions()[i].label as label">
            <input type="checkbox" [formControlName]="label" [id]="label" [name]="label"/>
            <label [for]="label">{{label}}</label>
          </div>
        </ng-container>
      </div>
    </form>

    {{planListForm.value | json}}
  `,
})
export class App {
  plansService = inject(PlansService);

  planListForm = this.formBuilder.group({
    carrierFilterOptions: this.formBuilder.array<CarrierFilterOption>([]),
  });

  get carrierFilterOptions(): FormArray {
    return this.planListForm.get('carrierFilterOptions') as FormArray;
  }

  constructor(private formBuilder: FormBuilder) {}

  get filterOptions() {
    return this.plansService.filterOptions;
  }

  ngOnInit() {
    this.plansService.getPlans().subscribe((data: CarrierFilterOption[]) => {
      this.plansService.filterOptions.set(data);
      this.plansService.filterOptions().forEach((filter) => {
        this.carrierFilterOptions.push(
          new FormGroup({
            [filter.label]: new FormControl(filter.isChecked),
          })
        );
      });
    });
  }
}

bootstrapApplication(App);

堆栈闪电战

© www.soinside.com 2019 - 2024. All rights reserved.