【问题标题】:Angular PatchValue Not Working When Called From Another Component从另一个组件调用时,Angular PatchValue 不起作用
【发布时间】:2019-04-28 18:34:39
【问题描述】:

我有一个组件从 firestore 获取文档集合并将它们显示在表格中,另一个组件具有反应式表单以向表格添加新条目。

我正在努力让用户单击表格上的按钮,然后使用该行中的数据填充反应式表单组件。

这是我在组件 A 中的表单:

  inventoryForm = new FormGroup({
    name: new FormControl('', Validators.required),
    date: new FormControl('', Validators.required),
    amount: new FormControl('', Validators.required),
    comment: new FormControl('', Validators.required),
    carried: new FormControl('', Validators.required),
  });

如果我在 componentA.html 中包含一个按钮,它在 componentA 中调用这样的函数

  testPatch() {
    this.inventoryForm.patchValue({ name: 'Test123' });
     }

表单已按预期更新(名称输入用 Test123 填充)。

但是,如果我在 componentB.html 中有一个按钮,该按钮调用 componentB 中的一个函数,然后调用 componentA 中的一个 patchValue 函数,则该补丁不起作用。

我将 componentA 导入到 componentB 以便在传递文档 ID 时调用该函数。

我是否缺少一些简单的东西,或者有更好的方法来尝试做到这一点?

更新:我遇到了表单组返回 null 的问题,我将添加一些额外的代码。

我必须更新 app.module.ts 中的 [providers] 以添加 FormGroupDirective,否则我会在尝试在组件的构造函数中初始化 FormGroupDirective 时遇到 stackinjector 错误。

app.component.ts

import { Component } from '@angular/core';
import { FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
import { InventoryService } from './inventory.service';
import { inventory_item } from './inventory_item';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {


  constructor(private inventoryService: InventoryService) {
  }

  inventoryForm = new FormGroup({
    name: new FormControl('', Validators.required),
    date: new FormControl('', Validators.required),
    amount: new FormControl('', Validators.required),
    comment: new FormControl('', Validators.required),
    carried: new FormControl('', Validators.required),
  });

  submitted = false;
  update = false;
  submittedItem: inventory_item = {
    name: '',
    date: '',
    amount: 0,
    comment: '',
    carried: '',
  }

  onSubmit() {
    this.submitted = true;
    const name = this.inventoryForm.get('name').value;
    const date = this.inventoryForm.get('date').value;
    const amount = this.inventoryForm.get('amount').value;
    const comment = this.inventoryForm.get('comment').value;
    const carried = this.inventoryForm.get('carried').value;
    this.inventoryService.addInventory({ name, date, amount, comment, carried })
    this.submittedItem = this.inventoryForm.value
  }
}

app.component.html

<app-inventory-list></app-inventory-list>
<div [hidden]="submitted">
  <form [formGroup]="inventoryForm" (ngSubmit)="onSubmit()">
    <label>
      Item Name:
      <input type="text" formControlName="name">
    </label>

    <label>
      Date Added:
      <input type="text" formControlName="date">
    </label>

    <label>
      Amount:
      <input type="number" formControlName="amount">
    </label>

    <label>
      Comment
      <input type="text" formControlName="comment">
    </label>

    <label>
      Carried by:
      <input type="text" formControlName="carried">
    </label>
    <br />
    <button type="submit" [disabled]="!inventoryForm.valid">Submit</button>
  </form>
</div>
<app-item-management></app-item-management>

<div [hidden]="!submitted">
  <h2>Item Added</h2>
  Name: {{submittedItem.name}}
  <br />
  Date: {{submittedItem.date}}
  <br />
  Amount: {{submittedItem.amount}}
  <br />
  Comment: {{submittedItem.comment}}
  <br />
  Carried by: {{submittedItem.carried}}
  <br />
  <button type="button"
          class="btn btn-default"
          (click)="inventoryForm.reset();
          submitted=false">
    New Loot!
  </button>
</div>

item-management.component.ts

import { Component, OnInit, Input } from '@angular/core';
import { InventoryService } from '../inventory.service';
import { FormGroupDirective, FormGroup, ControlContainer, FormControl, Validators } from '@angular/forms';

@Component({
  selector: 'app-item-management',
  templateUrl: './item-management.component.html',
  styleUrls: ['./item-management.component.css'],
  viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }]
})
export class ItemManagementComponent implements OnInit {


  constructor(private inventoryService: InventoryService, private parentForm: FormGroupDirective) {
  }

  editItem: any;

  ngOnInit() {
  }

  testPatch() {
    //this.parentForm.form.patchValue({ name: 'Test123' });
    console.log(this.parentForm.form)
  };

  updateInventory(updateId: string) {
  //this.parentForm.inventoryForm.patchValue({ name: 'Test123' });
    this.parentForm.form.patchValue({ name: 'Test123' });
    this.inventoryService.getUpdateInventoryItem(updateId)
      .then((doc) => {
        if (doc.exists) {
          console.log("Document data:", doc.data());
          this.editItem = doc.data();
          console.log("EditItem:", this.editItem)

        } else {
          console.log("No such document!");
        }
      }).catch(function (error) {
        console.log("Error getting document:", error);
      }); 
  };

}

item-management.component.html

<button type="button"
        class="btn btn-default"
        (click)="testPatch()">
  Patchtest
</button>

所以当我点击“补丁测试”按钮时,控制台会为返回的对象打印“null”,或者我得到:

Cannot read property 'patchValue' of null
    at ItemManagementComponent.push..

【问题讨论】:

    标签: angular google-cloud-firestore angular-reactive-forms reactive-forms


    【解决方案1】:

    更好的方法是创建顶级表单,然后将您的子组件包装在该组件中。

    app.component.ts

    <form [formGroup]="form">
        <input type="text" formControlName="name">
      <app-component-b></app-component-b>
    </form>
    

    在子组件内部使用 Viewproviders 获取 parentform 实例以使用

    修补值

    componentb.component.ts

    import { Component, OnInit } from '@angular/core';
    import { ControlContainer, FormGroupDirective } from '@angular/forms';
    @Component({
      selector: 'app-component-b',
      templateUrl: './component-b.component.html',
      styleUrls: ['./component-b.component.css'],
      viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }]
    })
    export class ComponentBComponent implements OnInit {
      constructor(private parentForm: FormGroupDirective) { }
      ngOnInit() {
      }
      patchValue() {
        this.parentForm.form.patchValue({ name: 'fromChildComponentB' });
      }
    
    }
    

    示例:https://stackblitz.com/edit/angular-jteaiw

    【讨论】:

    • 通过更改我的代码,当我尝试使用“this.parentForm.form.patchValue({ name: 'Test123' });"在孩子身上。
    • 我将代码添加到上面的初始问题中,感谢您查看。
    • 您应该将 item 项目管理组件移动到表单中
    • 是的,效果很好!再次感谢您的帮助。
    • 我很乐意提供帮助!
    猜你喜欢
    • 1970-01-01
    • 2019-07-05
    • 2023-03-24
    • 2021-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-07
    • 1970-01-01
    相关资源
    最近更新 更多