angular 2 模型驱动的嵌套表单组件 [英] angular 2 model driven nested form components

查看:33
本文介绍了angular 2 模型驱动的嵌套表单组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有什么:

我正在构建一个 ionic 2 应用程序并构建了一个基本的 angular 2 组件,其中包含

I am building an ionic 2 app and have built a basic angular 2 component that contains

  • 输入框

显示输入标题的标签

显示任何验证错误的标签

A label to display any validation errors

我将把它称为我的输入组件

I will refer to this as my input component

我有一个页面组件,上面有一个表单,目前有文本输入.1 个常规输入(密码)和 1 个包含在我的输入组件(用户名)中的输入.

I have a page component with a form on it, and currently have text inputs. 1 regular input (password) and 1 input wrapped in my input component (username).

这是我的页面组件的相关部分

ngOnInit() {
  this.loginForm = this.formBuilder.group({
    username: ['', Validators.required],
    password: ['', Validators.required]
  });
}

这是页面组件模板

<form [formGroup]="loginForm" (ngSubmit)="onSubmit()">

  <!-- My input component -->
  <aw-input-text id="username" name="Username" [formInput]="loginForm.controls.username"></aw-input-text>

  <!-- A standard input control -->
  <ion-item [class.error]="loginForm.controls.password.errors">
    <ion-label floating>Password</ion-label>
    <ion-input type="text" value="" name="password" formControlName="password"></ion-input>
    <p *ngIf="loginForm.controls.password.errors">This field is required!</p>
  </ion-item>

  <button type="submit" class="custom-button" [disabled]="!loginForm.valid" block>Login</button>

</form>

这是我的输入组件的模板

<!-- Component template -->
<form [formGroup]="formGroup">
    <ion-item>
        <ion-label floating>{{inputName}}</ion-label>
        <ion-input type="text" formControlName="inputValue"></ion-input>
        <p *ngIf="!formGroup.controls.inputValue.valid">This field is required!</p>
    </ion-item>
</form>

这是输入组件

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

@Component({
  selector: 'aw-input-text',
  templateUrl: 'build/shared/aw-input-text/aw-input-text.html'
})
export class AwInputText {

  @Input('formInput')
  public formInput;
  @Input('name')
  public inputName;
  public formGroup;
  constructor(private formBuilder: FormBuilder) {
  }

  ngOnInit() {
     this.formGroup = this.formBuilder.group({
        inputValue: this.formInput
     });
  }

}

组件正确呈现.

问题:

组件内部的输入不会更新它所在表单的有效状态.

The input inside the component doesn't update the valid state of the the form it is in.

当我填写用户名和密码时,表单就生效了

When I fill out the username then the password the form becomes valid

当我填写密码时,表单中的用户名仍然无效

When I fill out the password then the username the form remains invalid

所以表单可以看到输入组件的有效状态,只是输入组件改变有效状态不会触发表单更新.

So the form can see the valid state of the input component, it's just that the input component changing valid state doesn't trigger the form to update.

可能的解决方案 1

如本文所述和 plunk

As described in this article and plunk

https://scotch.io/tutorials/how-to-build-nested-model-driven-forms-in-angular-2

https://plnkr.co/edit/clTbNP7MHBbBbrUp20vr?p=preview

我可以修改我的页面组件来创建一个表单组,其中包含一个嵌套表单组,用于我想在输入组件中使用的每个表单控件

I could modify my page component to create a form group that contains a nested form group for every form control that I want to use inside of my input component

ngOnInit() {
  this.loginForm = this.formBuilder.group({
    username: this.formBuilder.group({
      username: ['', Validators.required],
    }),
    password: ['', Validators.required],
  });
}

此解决方案适合文章中添加输入控件数组的场景,但就我而言,我认为这感觉很糟糕

This solution fits the scenario in the article where they are adding an array of input controls, but in my case I think this feels hacky

可能的解决方案 2

我考虑过的另一个 hacky 解决方案是使用来自我的输入组件的 @output 指令来触发页面组件上的事件,每当输入组件更新时该事件都会刷新表单.

Another hacky solution I have considered is using an @output directive from my input component to trigger an event on the page component that refreshes the form whenever the input component is updated.

更新输入组件

this.formGroup.controls.inputValue.valueChanges.subscribe(value => {
  this.formUpdated.emit({
    value: value
  })
});

更新页面组件

public onUpdated(value){
  this.loginForm.updateValueAndValidity();
}

并更新页面组件模板

<aw-input-text id="username" name="Username" (updated)="onUpdated($event)" [formInput]="loginForm.controls.username"></aw-input-text>

这确实给了我想要的功能,但我认为在每个表单页面上都有一个事件处理程序来使输入组件工作似乎有点麻烦.

This does give me the desired functionality, but I think it also seems a bit hacky having an event handler on every form page to make the input component work.

问题

有没有办法让我的组件更新它所在表单的有效状态(请记住,我希望在每个表单中多次重复使用该组件),而无需求助于上述解决方案.

Is there a way for me to make my component update the valid state of the form it is in (keeping in mind that I would want to re-use this component multiple times in each form) without resorting to the solution described above.

推荐答案

感谢各位的回答.最后我们创建了两个组件,一个自定义表单组件和一个自定义输入组件.

Thanks for the answers guys. In the end we created two components, a custom-form component and a custom-input component.

我们将尽可能多的自定义输入组件嵌套在自定义表单组件中,并且自定义表单组件使用@ContentChildren 来识别和注册所有子自定义输入组件.

We nest as many custom-input components as we need inside the custom-form component and the custom-form component uses @ContentChildren to identify and register all the child custom-input components.

这样我们就不必将表单传递到每个输入中,并且我们不会为每个输入都有一堆嵌套的表单组.

This way we don't have to pass the form into every input, and we don't have a mess of nested form groups for every input.

// Each CustomInputText component exposes a FormControl and 
// a control definition which has additional info about the control
@ContentChildren(CustomInputText, {descendants: true})
public customInputComponents: QueryList<CustomInputText>;

private initialised;

public ngAfterContentChecked() {
  // Only initialise the form group once
  if (!this.initialised) {
    this.initialised = true;
    this.customInputComponents.forEach((input)=>{
        this.formGroup.addControl(input.controlDefinition.id, input.formControl); 
    });
  }
}

这篇关于angular 2 模型驱动的嵌套表单组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆