简体   繁体   English

如何使用当前的 Form API 将父组件的 FormGroup 传递给其子组件

[英]How can I pass the FormGroup of a parent component to its child component using the current Form API

I would like to pass the parent component's FormGroup to its child for the purpose of displaying an error-message using the child.我想将父组件的FormGroup给它的子组件,以便使用子组件显示错误消息。

Given the following parent:给定以下父级:

parent.component.ts父组件.ts

import { Component, OnInit } from '@angular/core'
import {
  REACTIVE_FORM_DIRECTIVES, AbstractControl, FormBuilder, FormControl, FormGroup, Validators
} from '@angular/forms'

@Component({
  moduleId: module.id,
  selector: 'parent-cmp',
  templateUrl: 'language.component.html',
  styleUrls: ['language.component.css'],
  directives: [ErrorMessagesComponent]
})
export class ParentCmp implements OnInit {
  form: FormGroup;
  first: AbstractControl;
  second: AbstractControl;
  
  constructor(private _fb: FormBuilder) {
    this.first = new FormControl('');
    this.second = new FormControl('')
  }
  
  ngOnInit() {
    this.form = this._fb.group({
      'first': this.first,
      'second': this.second
    });
  }
}

I would now like to pass the form:FormGroup variable above to the child component below:我现在想将上面的 form:FormGroup 变量传递给下面的子组件:

error-message.component.ts错误消息.component.ts

import { Component, OnInit, Input } from '@angular/core'
import { NgIf } from '@angular/common'
import {REACTIVE_FORM_DIRECTIVES, FormGroup } from '@angular/forms'

@Component({
  moduleId: module.id,
  selector: 'epimss-error-messages',
  template: `<span class="error" *ngIf="errorMessage !== null">{{errorMessage}}</span>`,
  styles: [],
  directives: [REACTIVE_FORM_DIRECTIVES, NgIf]  
})
export class ErrorMessagesComponent implements OnInit {
  @Input() ctrlName: string

  constructor(private _form: FormGroup) { }

  ngOnInit() { }

  get errorMessage() {
    // Find the control in the Host (Parent) form
    let ctrl = this._form.find(this.ctrlName);
    console.log('ctrl| ', ctrl);

//    for (let propertyName of ctrl.errors) {
//      // If control has a error
//      if (ctrl.errors.hasOwnProperty(propertyName) && ctrl.touched) {
//        // Return the appropriate error message from the Validation Service
//        return CustomValidators.getValidatorErrorMessage(propertyName);
//      }
//    }

    return null;
  }

The constructor formGroup represents the FormGroup of the parent - in its present form it does not work.构造函数 formGroup 代表父级的 FormGroup - 在其当前形式中它不起作用。

I am trying to follow this obsolete example at http://iterity.io/2016/05/01/angular/angular-2-forms-and-advanced-custom-validation/我试图在http://iterity.io/2016/05/01/angular/angular-2-forms-and-advanced-custom-validation/遵循这个过时的例子

In the parent component do this:在父组件中这样做:

<div [formGroup]="form">
  <div>Your parent controls here</div>
  <your-child-component [formGroup]="form"></your-child-component>
</div>

And then in your child component you can get hold of that reference like so:然后在您的子组件中,您可以像这样获取该引用:

export class YourChildComponent implements OnInit {
  public form: FormGroup;

  // Let Angular inject the control container
  constructor(private controlContainer: ControlContainer) { }

  ngOnInit() {
    // Set our form property to the parent control
    // (i.e. FormGroup) that was passed to us, so that our
    // view can data bind to it
    this.form = <FormGroup>this.controlContainer.control;
  }
}

You can even ensure either formGroupName or [formGroup] is specified on your component by changing its selector like so:您甚至可以通过像这样更改其选择器来确保在您的组件上指定了formGroupName[formGroup]

selector: '[formGroup] epimss-error-messages,[formGroupName] epimss-error-messages'

This answer should be sufficient for your needs, but if you want to know more I've written a blog entry here:这个答案应该足以满足您的需求,但如果您想了解更多信息,我在这里写了一篇博客文章:

https://mrpmorris.blogspot.co.uk/2017/08/angular-composite-controls-formgroup-formgroupname-reactiveforms.html https://mrpmorris.blogspot.co.uk/2017/08/angular-composite-controls-formgroup-formgroupname-reactiveforms.html

this is an example of child component used inside parent formGroup : child component ts:这是在父 formGroup 中使用的子组件的示例:子组件 ts:

import { Component, OnInit, Input } from '@angular/core';
import { FormGroup, ControlContainer, FormControl } from '@angular/forms';


@Component({
  selector: 'app-date-picker',
  template: `
  <mat-form-field [formGroup]="form" style="width:100%;">
  <input matInput [matDatepicker]="picker" [placeholder]="placeHolder" [formControl]="control" readonly>
  <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
  <mat-datepicker #picker></mat-datepicker>
</mat-form-field>
<mat-icon (click)="clearDate()">replay</mat-icon>`,
  styleUrls: ['./date-picker.component.scss']
})

export class DatePickerComponent implements OnInit {
  public form: FormGroup;
  public control : FormControl;
  @Input() controlName : string;
  @Input() placeHolder : string;


  constructor(private controlContainer: ControlContainer) { 
  }

  clearDate(){
    this.control.reset();
  }

  ngOnInit() {
    this.form = <FormGroup>this.controlContainer.control;
    this.control = <FormControl>this.form.get(this.controlName);
    }

}

css date picker : css日期选择器:

mat-icon{
position: absolute;
left: 83%;
top: 31%;
transform: scale(0.9);
cursor: pointer;
}

and used like this :并像这样使用:

 <app-date-picker class="col-md-4" [formGroup]="feuilleForm" controlName="dateCreation" placeHolder="Date de création"></app-date-picker>

Parent Component :父组件:

    @Component({
      selector: 'app-arent',
      templateUrl: `<form [formGroup]="parentFormGroup" #formDir="ngForm">
                       <app-child [formGroup]="parentFormGroup"></app-child>
                    </form>         `
    })
    
    export class ParentComponent implements {
        
     parentFormGroup :formGroup
    
     ngOnChanges() {        
       console.log(this.parentFormGroup.value['name'])
     }
  }

Child Component :子组件:

    @Component({
      selector: 'app-Child',
      templateUrl: `<form [formGroup]="childFormGroup" #formDir="ngForm">
                        <input id="nameTxt" formControlName="name">
                    </form>         `
    })
    
    export class ChildComponent implements OnInit {
     @Input()  formGroup: FormGroup
    
     childFormGroup :FormGroup
    
    ngOnInit() {
      // Build your child from
      this.childFormGroup.addControl('name', new FormControl(''))
    
      /* Bind your child form control to parent form group
         changes in 'nameTxt' directly reflect to your parent 
         component formGroup
        */          
     this.formGroup.addControl("name", this.childFormGroup.controls.name);
   
     }
  }

For Angular 11 I tried all the above answers, and in different combinations, but nothing quite worked for me.对于 Angular 11,我尝试了上述所有答案,并采用了不同的组合,但对我来说没有任何效果。 So I ended up with the following solution which worked for me just as I wanted.所以我最终得到了以下解决方案,正如我想要的那样对我有用。

TypeScript打字稿

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

  valueFormGroup?: FormGroup;
  valueFormControl?: FormControl;

  constructor(
    private formGroupDirective: FormGroupDirective, 
    private formControlNameDirective: FormControlName
  ) {}

  ngOnInit() {
    this.valueFormGroup = this.formGroupDirective.form;
    this.valueFormControl = this.formGroupDirective.getControl(this.formControlNameDirective);
  }

  get controlName() {
    return this.formControlNameDirective.name;
  }

  get enabled() {
    return this.valueFormControl?.enabled
  }

}

HTML HTML

<div *ngIf="valueFormGroup && valueFormControl">
    <!-- Edit -->
    <div *ngIf="enabled; else notEnabled" [formGroup]="valueFormGroup">
        <input class="input" type="text" [formControlName]="controlName">        
    </div>
    <!-- View only -->
    <ng-template #notEnabled>
        <div>
            {{valueFormControl?.value}}
        </div>
    </ng-template>
</div>

Usage用法

Note that I had to add ngDefaultControl otherwise it would give no default value accessor error in console (if somebody knows how to get rid of it without error - will be much appreciated).请注意,我必须添加ngDefaultControl否则它不会在控制台中给出默认值访问器错误(如果有人知道如何无误地摆脱它 - 将不胜感激)。

<form [formGroup]="yourFormGroup" (ngSubmit)="save()">
    <fancy-input formControlName="yourFormControlName" ngDefaultControl></fancy-input>
</form>

I would pass the form as an input to the child component;我会将表单作为输入传递给子组件;

@Component(
    {
      moduleId: module.id,
      selector: 'epimss-error-messages',
      template: `
   <span class="error" *ngIf="errorMessage !== null">{{errorMessage}}</span>`,
      styles: [],
      directives: [REACTIVE_FORM_DIRECTIVES, NgIf]

    })
export class ErrorMessagesComponent implements OnInit {
  @Input()
  ctrlName: string

  @Input('form') _form;

  ngOnInit() {
         this.errorMessage();
      }

  errorMessage() {
    // Find the control in the Host (Parent) form
    let ctrl = this._form.find(this.ctrlName);

    console.log('ctrl| ', ctrl)

//    for (let propertyName of ctrl.errors) {
//      // If control has a error
//      if (ctrl.errors.hasOwnProperty(propertyName) && ctrl.touched) {
//        // Return the appropriate error message from the Validation Service
//        return CustomValidators.getValidatorErrorMessage(propertyName);
//      }
//    }

    return null;
  }

And of course you'll need o pass the form from the parent component to the child, which you can do it in different ways , but the simplest is :当然,您需要将表单从父组件传递给子组件,您可以通过不同的方式来实现,但最简单的是:

Somewhere in your parent ;在你父母的某个地方;

     <epimss-error-messages [form]='form'></epimss-error-messages>

If you want to access the parent from the child component, you can access parent property of the FormControl instance, https://angular.io/api/forms/AbstractControl#parent如果要从子组件访问父组件,可以访问 FormControl 实例的 parent 属性, https: //angular.io/api/forms/AbstractControl#parent

To get the parent error:要获取父错误:

const parent = control.parent;
const errors = parent.errors;

The ngOnInit was important - this did not work in the constructor. ngOnInit很重要 - 这在构造函数中不起作用。 And I prefer looking for the FormControlDirective - its the first one found in the child component's ancestor hierarchy我更喜欢寻找FormControlDirective - 它是在子组件的祖先层次结构中找到的第一个

constructor(private formGroupDirective: FormGroupDirective) {}

  ngOnInit() {
    this.formGroupDirective.control.addControl('password', this.newPasswordControl);
    this.formGroupDirective.control.addControl('confirmPassword', this.confirmPasswordControl);
    this.formGroup = this.formGroupDirective.control;
  }

I would do this in this way, i have passed child form data as group to parent so you can have separated form data in submit call.我会以这种方式执行此操作,我已将子表单数据作为组传递给父级,因此您可以在提交调用中分离表单数据。

Parent:家长:

<form [formGroup]="registerStudentForm" (ngSubmit)="onSubmit()">
<app-basic-info [breakpoint]="breakpoint" [formGroup]="registerStudentForm"></app-basic-info>
<button mat-button>Submit</button>
</form>

Child:孩子:

<mat-card [formGroup]="basicInfo">
    <mat-card-title>Basic Information</mat-card-title>
    <mat-card-content>
      <mat-grid-list
        [gutterSize]="'20px'"
        [cols]="breakpoint"
        rowHeight="60px"
      >
        <mat-grid-tile>
          <mat-form-field appearance="legacy" class="full-width-field">
            <mat-label>Full name</mat-label>
            <input matInput formControlName="full_name" />
          </mat-form-field>
        </mat-grid-tile>
    </mat-grid-list>
</mat-card-content>
</mat-card>

Parent.ts:父母.ts:

export class RegisterComponent implements OnInit {
    constructor() { }

    registerForm = new FormGroup({});
  
    onSubmit() {
      console.warn(this.registerForm.value);
    }
  
  }

Child.ts Child.ts

export class BasicInfoComponent implements OnInit {
  @Input() breakpoint;
  @Input() formGroup: FormGroup;
  basicInfo: FormGroup;
  constructor() { }

  ngOnInit(): void {
    this.basicInfo = new FormGroup({
      full_name: new FormControl('Riki maru'),
      dob: new FormControl(''),
    });
    this.formGroup.addControl('basicInfo', this.basicInfo);
  }
}

Here in your child form components @Input() formGroup: FormGroup;在您的子表单组件中@Input() formGroup: FormGroup; part would be reference of parent component部分将是父组件的参考

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Angular 4 FormGroup-将父表单控件传递给子组件 - Angular 4 FormGroup - Pass parent form controls to child component 如何让父组件成为其子组件的标签? - How can I make a parent component be the label of its child component? 如何将子组件的验证数据(作为表单表单)传递给其父组件并处理父组件中的表单提交 - how to pass a child component's validated data (as a formik form) to its parent component and handle form submission in parent 如何将状态从这个子组件传递给父组件? - How can I pass the state from this child to parent component? 如何将子组件的 state 传递给父组件? - How can I pass a child component's state up to the parent? 在React.js的父组件中使用react-router时,如何使用react context API将数据从父组件传递到子组件? - How do I use react context API to pass data from parent component to child component when using react-router in the parent component in React.js? 当它作为道具传递时,如何将状态从父组件更新到子组件? - How can I update the state from parent component to child component when its passed as a prop? ReactJS 类 如何将 State 从子组件传递给其父组件? - ReactJS Classes How to pass State from Child Component to its Parent? 当我使用 React Hooks 将 boolean 从子组件传递到其父组件时出现了什么问题? - What is going wrong when I pass a boolean from a child to its parent component using React Hooks? 如何通过道具[REACT.JS]将图片网址从父组件传递到子组件 - How can I pass image url from parent component to child component via props [REACT.JS]
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM