简体   繁体   English

如何在 angular 中验证子组件上的模板驱动表单

[英]How to validate Template-Driven-Forms on children components in angular

I am working on Angular 10. Its been 3 days that I have a problem with angular template-driven and reactive forms.我正在研究 Angular 10。我已经 3 天遇到 angular 模板驱动和反应式 forms 的问题。

What I want to do: Create a complex form with many child components (in order to separate lot of code).我想做什么:创建一个包含许多子组件的复杂表单(以便分离大量代码)。 Then on one button click I want to validate all the form and the child components.然后单击一个按钮,我想验证所有表单和子组件。 I want somehow to validate children components.我想以某种方式验证子组件。

What I created: A template-driven form with 2-way bindings because I believe its easier and not needed for my situation.我创建的内容:具有双向绑定的模板驱动表单,因为我相信它更容易,而且我的情况不需要。

I have managed to make the validation work only for the base form.我设法使验证仅适用于基本表单。 I couldn't do it on the children components.我无法在子组件上执行此操作。 I saw many posts about this issue and tried a lot but I am very confused.我看到很多关于这个问题的帖子并尝试了很多,但我很困惑。

My code:我的代码:

mainForm.html mainForm.html

<div class="card m-3">
    
    <div class="card-body">
      <fieldset>
        <form name="form" (ngSubmit)="f.form.valid && onSubmit()" #f="ngForm" novalidate>
        
            <div class="form-row">
                <div class="form-group col">
                    <label>Title</label>
                    <select name="title" class="form-control" [(ngModel)]="model.title" #title="ngModel" [ngClass]="{ 'is-invalid': f.submitted && title.invalid }" required>
                        <option value=""></option>
                        <option value="Mr">Mr</option>
                        <option value="Mrs">Mrs</option>
                        <option value="Miss">Miss</option>
                        <option value="Ms">Ms</option>
                    </select>
                    <div *ngIf="f.submitted && title.invalid" class="invalid-feedback">
                        <div *ngIf="title.errors.required">Title is required</div>
                    </div>
                </div>
                <div class="form-group col-5">
                    <label>First Name</label>
                    <input type="text" name="firstName" class="form-control" [(ngModel)]="model.firstName" #firstName="ngModel" [ngClass]="{ 'is-invalid': f.submitted && firstName.invalid }" required>
                    <div *ngIf="f.submitted && firstName.invalid" class="invalid-feedback">
                        <div *ngIf="firstName.errors.required">First Name is required</div>
                    </div>
                </div>
                <div class="form-group col-5">
                    <label>Last Name</label>
                    <input type="text" name="lastName" class="form-control" [(ngModel)]="model.lastName" #lastName="ngModel" [ngClass]="{ 'is-invalid': f.submitted && lastName.invalid }" required>
                    <div *ngIf="f.submitted && lastName.invalid" class="invalid-feedback">
                        <div *ngIf="lastName.errors.required">Last Name is required</div>
                    </div>
                </div>
            </div>
            
            <div class="form-row">
                <div class="form-group col">
                    <label>Date of Birth</label>
                    <input type="date" name="dob" class="form-control" [(ngModel)]="model.dob" #dob="ngModel" [ngClass]="{ 'is-invalid': f.submitted && dob.invalid }" required pattern="^\d{4}\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01])$">
                    <div *ngIf="f.submitted && dob.invalid" class="invalid-feedback">
                        <div *ngIf="dob.errors.required">Date of Birth is required</div>
                        <div *ngIf="dob.errors.pattern">Date of Birth must be a valid date in the format YYYY-MM-DD</div>
                    </div>
                </div>             
            </div>

>  One child component for demonstration(there are more)--code continues below

              <app-extra-info  [(model)]="model"></app-extra-info> pass model in children
  
            <div class="text-center">
                <button class="btn btn-primary mr-1">Register</button>            
            </div>
        </form>
      </fieldset>
  </div>
</div>

childcomponent.html:子组件.html:

  <div class="form-group row">
    <label class="col-2 col-form-label">Gender</label>
    <div class="col-4">
      <select id="gender" name="gender" class="form-control"  required>
        <option>Male</option>
        <option>Female</option>
         <option>Not Specify</option>
         <option></option>
      </select>        
    </div>   
  </div>

  <div class="form-group row">
    <label>Pet name</label>
    <input type="text" name="petName" class="form-control" [(ngModel)]="model.petName" #petName="ngModel" [ngClass]="{ 'is-invalid': petName.invalid && petName.dirty}" required>
    <div *ngIf="petName.invalid" class="invalid-feedback">
        <div *ngIf="petName.errors.required">Pet Name is required</div>
    </div>
  </div>

childrencomponent.ts:儿童组件.ts:

import { Component, Input, OnInit } from '@angular/core';

@Component({
  selector: 'app-extra-info',
  templateUrl: './extra-info.component.html',
  styleUrls: ['./extra-info.component.css']
})
export class ExtraInfoComponent implements OnInit {

  @Input() model: any;
  
  constructor() { }

  ngOnInit(): void {
  }

}

parent.ts父母.ts

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-user-settings-form',
  templateUrl: './user-settings-form.component.html',
  styleUrls: ['./user-settings-form.component.css']
})
export class UserSettingsFormComponent implements OnInit {

  model: any = {};

  constructor() {

   }

  ngOnInit() {
    
  }

  onSubmit() {
    alert(JSON.stringify(this.model, null, 4));
  }

} }

The code works as it is.代码按原样工作。 The problem is that when I press Register, anything in the children component wont get validated.(in this case Pet name and gender)问题是当我按下 Register 时,子组件中的任何内容都不会得到验证。(在本例中为宠物名称和性别)

Demo picture: Form演示图片:表格

Questions I have:我的问题:

  1. Do I need to use template-driven or reactive forms?我需要使用模板驱动还是反应式 forms? I said before that template-driven forms are easier and not needed for my situation but, I am not quite sure about this.我之前说过模板驱动的 forms 更容易,我的情况不需要,但我不太确定这一点。

  2. Do I need to pass the form into the children or pass children to main form?我需要将表格传递给孩子还是将孩子传递给主表格? Is there a way to implement validation to children components using Template driven form?有没有办法使用模板驱动表单对子组件实施验证?

Please can someone enlighten me what is the correct thing to do, give me some feedback and any suggestion.请有人告诉我什么是正确的做法,给我一些反馈和任何建议。 Don't hesitate to ask me anything or if you want more details.如果您需要更多详细信息,请随时问我任何问题。

Thank you for your time.感谢您的时间。

The response before - in my opinion - it is a hackish response, which brings extra burden to your typescript code and bypasses the framework mechanisms.之前的响应 - 在我看来 - 这是一个 hackish 响应,它给你的 typescript 代码带来额外的负担并绕过框架机制。 It is specially overkilling when you're using template-drive forms - which require no typescript code to control the form.当您使用模板驱动 forms 时,它特别矫枉过正——它不需要 typescript 代码来控制表单。

The solution?解决方案? Use what the framework provides (inside your child @Component({})):使用框架提供的内容(在你的孩子 @Component({}) 中):

viewProviders: [{provide: ControlContainer, useExisting: NgForm}]

For a working example of this see this repository有关此的工作示例,请参阅此存储库

You can pass in a formControl :您可以传入一个formControl

 @Input() formControl: FormControl;

Then pass it like this然后像这样传递

  <app-extra-info  [formControl]="f.get('petName')"></app-extra-info> pass model in children

then pass the form to the submit然后将表单传递给提交

<form name="form" (ngSubmit)="onSubmit(f.form)" #f="ngForm" novalidate>


onSubmit(form: FormGroup) {
    form.get('petName').updateValueAndValidity();

    alert( form.get('petName').valid);
  }

I have managed to implement something that is working.我已经设法实现了一些有效的东西。

What I have done is to add @ViewChild(ChildComponent) child-Component: ChildComponent;我所做的是添加@ViewChild(ChildComponent) child-Component: ChildComponent; in parent.ts.在 parent.ts 中。

Then in child component I have created a function that checks the children form and if there are any errors I return a Boolean variable.然后在子组件中,我创建了一个函数来检查子表单,如果有任何错误,我将返回一个布尔变量。 That function is used in parent.该函数用于父级。 I am doing this for each children.我正在为每个孩子做这件事。 Shortly, I am doing form validation in each child component and I am getting a Boolean variable in parent.不久,我在每个子组件中进行表单验证,并且在父组件中获得一个布尔变量。

In parent I have something like :在父母中,我有类似的东西:

if (!this.child-Component.validform) {
        console.log("child has missing inputs");
      }

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM