【问题标题】:Angular5/4+: Populate nested ReactiveForm using API callAngular 5/4+:使用 API 调用填充嵌套的反应式表单
【发布时间】:2018-04-17 00:47:52
【问题描述】:

我正在尝试填充嵌套的ReactiveForm,它被分成几个子表单组件。一旦 API 请求完成,我就可以填充父表单,但不能将子 FormArray 完全循环到子数据的计数。以下是我的代码中的 sn-ps:

编辑视图:edit.component.ts

@Component({
  selector: 'app-edit',
  templateUrl: './edit.component.html',
  styleUrls: ['./edit.component.scss']
})
export class EditComponent implements OnInit {

  public data: Service = new Service({
            id: '',
            title: '',
            description: '',
            service_extras: []
        });    
  public routeParams: any = {};    
  constructor ( 
    private route: ActivatedRoute,
    private service: ServicesService
  ) { }

  ngOnInit() {
    this.setRouteParams();
  }

  setRouteParams() {
    this.route.params.subscribe(params => {
        this.routeParams = params;
      // getting services using api call
        this.getService(this.routeParams);
    });
  }

  getService(params) {
    this.service
    .getService(params.id)
    .subscribe((service: Service) => {
        this.data = service;
    });
  }

}

我在基础edit.component.ts 组件中请求数据并将接收到的数据传递给父表单组件,它是EditComponent 的子组件

edit.component.html

<service-form [serviceFormData]="data"></service-form>

service-form.component.ts

@Component({
    selector: 'service-form',
    templateUrl: './service-form.component.html',
    styleUrls: ['./service-form.component.scss']
})
export class ServiceFormComponent implements OnInit {

    private _serviceFormData = new BehaviorSubject<Service>(null);    
    @Input()
    set serviceFormData(value) {
        this._serviceFormData.next(value);
    }        
    get serviceFormData() {
        return this._serviceFormData.getValue();
    }    
    public service: Service;
    public serviceForm: FormGroup;

    constructor(
        private fb: FormBuilder
    ) { }

    ngOnInit() {    
        this.serviceForm = this.toFormGroup();
        this._serviceFormData.subscribe(data => {
            this.serviceForm.patchValue(data);
        });
    }

    private toFormGroup(): FormGroup {           
        const formGroup = this.fb.group({
            id: [ '' ],
            title: [ '' ],
            description: [ '' ]
        });    
        return formGroup;
    }
}

我在@Input var 的帮助下通过订阅其更改然后将值修补到表单来接收数据,现在一切正常,因为一旦收到数据,所有字段都会被填充。问题出在下面:

service-extra.component.ts

@Component({
  selector: 'service-extra-form',
  templateUrl: './service-extra.component.html',
  styleUrls: ['./service-extra.component.scss']
})
export class ServiceExtraComponent implements OnInit {    
  private _extraFormData = new BehaviorSubject<ServiceExtra[]>([]);

  @Input() serviceForm: FormGroup;    
  @Input() 
  set extraFormData(value: ServiceExtra[]) {
    this._extraFormData.next(value);
  }    
  get extraFormData() {
    return this._extraFormData.getValue();
  }

  public extrasForm: FormGroup;

  constructor(private fb: FormBuilder) { }

  ngOnInit()
  {
    this.serviceForm.addControl('service_extras', new FormArray([]));    
    this._extraFormData.subscribe(data => {
      this.addNew();
      this.extras.patchValue(data);
    });

  }

  private toFormGroup()
  {
    const formGroup = this.fb.group({
      id: [''],
      service_id: [''],
      title: ['']
    });    
    return formGroup;
  }

  public addNew()
  {
    this.extrasForm = this.toFormGroup();        (<FormArray>this.serviceForm.controls.service_extras).push(this.extrasForm);
  }

  public removeThis(i: number)
  {
    (<FormArray>this.serviceForm.controls.service_extras).removeAt(i);
  }


  get extras(): FormArray {
     return this.serviceForm.get('service_extras') as FormArray;
  }

}

ngOnInit 上面的代码除了添加单个 extras 表单(即使有两条记录)并填充该表单之外什么都不做,即使我删除了订阅部分并仅使用 this.addNew(),这种情况也是一样的。我怎么知道ServiceExtras 有多少条记录,以便我可以将那么多FormGroups 添加到FormArray

编辑 1

Stackblitz Demo

编辑 2

问题是如果有两条来自 API 的记录用于额外服务,那么我无法生成两个 FormGroups 并用数据填充它们,因为在渲染时我无法检测到有多少记录来自服务额外来自 API。

【问题讨论】:

  • 你能在 stackblitz 上演示你的问题吗?
  • @yurzui 我已经编辑了我的问题以添加 Stackblitz 演示
  • 查看代码,还是没看懂是什么问题。您何时知道 ServiceExtras 有多少条记录?
  • @trungk18 实际上的问题是,如果他们有 2 条记录需要额外服务,那么它只会填充一个,而发生这种情况是因为我将 1 个表单组推送到 service_extra&lt;FormArray&gt;...我的问题是我无法检测到有多少 service_extra 记录来自 API,因此我可以生成那么多 FormGroups 并且推送到 &lt;FromArray&gt;service_extras,这有意义吗?

标签: angular typescript mean-stack


【解决方案1】:

service-form.component.html 中,您将serviceForm.value.service_extras 属性绑定到extraFormData。但是在service-extra-form 组件初始化之前serviceForm 没有service_extras formArray。并且在初始化之后。 service-extra-form 组件,你调用 addRow() 方法,它用一行准确地填写表单:

service-extra.component.ts

 ngOnInit()
  {
    this.serviceForm.addControl('service_extras', new FormArray([]));    
    this._extraFormData.subscribe(data => {
      console.log('service_extra_data', data);
      this.addNew();
      this.extras.patchValue(data);
    });

  }

service-form.component.html:

<service-extra-form [serviceForm]="serviceForm" 
                    [extraFormData]="serviceForm.value.service_extras">
 </service-extra-form> 

将 [serviceForm] 传递给 service-extra-form 就足够了。如果你已经通过了form,为什么还要通过serviceForm.value.service_extras

修复,删除多余的代码。用更少的代码做同样的事情?

ServiceExtraComponent

export class ServiceExtraComponent implements OnInit {
  @Input() serviceForm: FormGroup;
  @Input() extraFormData: ServiceExtra[];

  public extrasForm: FormGroup;

  constructor(private fb: FormBuilder) { }

 ngOnChanges(data) {
    //console.log('ngOnChanges', data);

    // if changes only extraFormData
    if (data.extraFormData) {
      this.extras.setValue([]); // reset
      let newExtraArr = data.extraFormData.currentValue;

      for (let i = 0; i < newExtraArr.length; i++) {
        this.addNew();
        this.extras.patchValue(newExtraArr);
      }
    }
  } 

  ngOnInit() {
    this.serviceForm.addControl('service_extras', new FormArray([]));
  }

@Input() extraFormData: ServiceExtra[]; 这里从 api 传递 extra_data 并在 ngOnChanges lyfecycle 挂钩上,重置 serviceForm 的 service_extras formArray

StackBlitz Demo

【讨论】:

  • 谢谢你的回答我会看看答案告诉你。
  • 该解决方案对我有用,@PierreMallet 提供的解决方案也可以正常工作。我现在很困惑将哪个标记为已接受,哪个奖励是赏金。非常感谢您的宝贵意见
  • @SagarGuhe,很高兴为您提供帮助✌?
【解决方案2】:

这是一个修复 (stackblitz here)

问题行为的解释:

您的输入是这样声明的:

<service-extra-form [serviceForm]="serviceForm" [extraFormData]="serviceForm.value.service_extra"></service-extra-form>

所以输入是表单的值,而不是来自 api 的值。

但是当您在对 api 进行异步调用后填充表单时,“发送”到 ServiceExtraComponent 的第一个值是 undefined,在您调用的 ServiceExtraComponent ngOnInit

this.addNew();
this.extras.patchValue(data); 

data = undefined

它在 formArray 中创建一个新的 formGroup,然后用 undefined 打补丁。

因此,当 API 响应您的表单时,您的表单已经使用包含一项的 formArray 创建,因此patchValue 会截断您的 service_extra 数组以匹配您的表单。

更正可能是将 API 的返回直接绑定为 ServiceExtraComponent Input aka :

<service-extra-form [serviceForm]="serviceForm" [extraFormData]="serviceFormData.service_extras"></service-extra-form>

【讨论】:

  • 该解决方案对我有用,@Yerkon 提供的解决方案也可以正常工作。我现在很困惑将哪个标记为已接受,哪个奖励是赏金。非常感谢您的宝贵意见
  • 拿 yerkon 的。 ?
猜你喜欢
  • 2019-02-01
  • 2018-06-22
  • 1970-01-01
  • 2017-07-20
  • 1970-01-01
  • 2017-09-27
  • 1970-01-01
  • 1970-01-01
  • 2018-07-04
相关资源
最近更新 更多