Javascript 需要使用角度2从两个字段中选择一个

Javascript 需要使用角度2从两个字段中选择一个,javascript,html,angular,Javascript,Html,Angular,我正在尝试创建一个联系人表单。表单如下所示: <form novalidate [formGroup]="contact" (ngSubmit)="send()"> <p> <label>Name <br> <input type="text" class="input" value="" formControlName="name"> <span class="error">

我正在尝试创建一个联系人表单。表单如下所示:

<form novalidate [formGroup]="contact" (ngSubmit)="send()">
  <p>
    <label>Name
      <br>
      <input type="text" class="input" value="" formControlName="name">
      <span class="error">Enter your name</span>
    </label>
  </p>
  <p>
    <label>E-mail
      <br>
      <input type="email" class="input" value="" formControlName="email">
      <span class="error">It looks like this email is invalid</span>
    </label>
  </p>
  <p>
    <label>Phone
      <br>
      <input type="text" class="input" value="" formControlName="telefone">
      <span class="error">It looks like this phone number is invalid</span>
    </label>
  </p>
  <p>
    <label>Message
      <br>
      <textarea type="text" class="input" value="" formControlName="message"></textarea>
      <span class="error">The message can't be empty</span>
    </label>
  </p>
  <p class="submit">
    <input type="submit" name="submit" class="bt" value="Send">
  </p>
</form>
this.contact = this.formBuilder.group({
  name: ['', Validators.required],
  email: ['', Validators.required],
  phone: ['', Validators.required],
  message: ['', Validators.required]
}, {validator: this.customValidationFunction})

我尝试使用自定义验证器作为解决方案,但我找不到解决方案。有什么建议吗?

是的,定制验证器是最好的选择

使您的表单组如下所示:

<form novalidate [formGroup]="contact" (ngSubmit)="send()">
  <p>
    <label>Name
      <br>
      <input type="text" class="input" value="" formControlName="name">
      <span class="error">Enter your name</span>
    </label>
  </p>
  <p>
    <label>E-mail
      <br>
      <input type="email" class="input" value="" formControlName="email">
      <span class="error">It looks like this email is invalid</span>
    </label>
  </p>
  <p>
    <label>Phone
      <br>
      <input type="text" class="input" value="" formControlName="telefone">
      <span class="error">It looks like this phone number is invalid</span>
    </label>
  </p>
  <p>
    <label>Message
      <br>
      <textarea type="text" class="input" value="" formControlName="message"></textarea>
      <span class="error">The message can't be empty</span>
    </label>
  </p>
  <p class="submit">
    <input type="submit" name="submit" class="bt" value="Send">
  </p>
</form>
this.contact = this.formBuilder.group({
  name: ['', Validators.required],
  email: ['', Validators.required],
  phone: ['', Validators.required],
  message: ['', Validators.required]
}, {validator: this.customValidationFunction})
然后让
customValidationFunction
检查验证。虚构验证,例如:

customValidationFunction(formGroup): any {
   let nameField = formGroup.controls['name'].value; //access any of your form fields like this
   return (nameField.length < 5) ? { nameLengthFive: true } : null;
}
customValidationFunction(formGroup):任何{
让nameField=formGroup.controls['name'].value;//像这样访问任何表单字段
返回值(nameField.length<5){nameLengthFive:true}:null;
}
按如下方式更改每个输入(将p标记更改为divs。在适当的情况下,为每个输入替换控件名称,并更改隐藏范围标记验证的语法):


名称
输入您的姓名

我创建了一个自定义验证器指令:

import {
    FormGroup,
    ValidationErrors,
    ValidatorFn,
    Validators,
  } from '@angular/forms';

  export const atLeastOne = (validator: ValidatorFn, controls:string[] = null) => (
    group: FormGroup,
  ): ValidationErrors | null => {
    if(!controls){
      controls = Object.keys(group.controls)
    }

    const hasAtLeastOne = group && group.controls && controls
      .some(k => !validator(group.controls[k]));

    return hasAtLeastOne ? null : {
      atLeastOne: true,
    };
  };
要使用它,您只需执行以下操作:

this.form = this.formBuilder.group({
            name: ['', Validators.required],
            email:[''],
            telefone:[''],
            message:['', Validators.required],
        }, { validator: atLeastOne(Validators.required, ['email','telefone']) });
因此这里需要
电子邮件
电话
。如果将其保留为空,则任何具有值的控件都可以,并且您可以将其与任何类型的验证器一起使用,而不仅仅是
验证器。必选

这可以以任何形式重复使用

我已经更新了我的验证器代码段,以支持字符串和数字类型

我的灵感来自托德·斯凯尔顿。这是一个非常简单的验证器,只执行您要求的操作,而不执行其他操作:

/**
*验证提供的字段中是否至少有一个具有值。
*字段只能是number或string类型。
*@param fields应检查的表单字段的名称
*/
导出函数atLeastOne(…字段:字符串[]){
返回(fg:FormGroup):ValidationErrors | null=>{
返回字段。一些(字段名=>{
const field=fg.get(fieldName).value;
如果(字段类型=='number')返回字段和字段>=0,则为true:false;
如果(typeof field==='string')返回字段和field.length>0,则为true:false;
})
无效的
:({atlestone:'必须至少提供一个字段。}作为ValidationErrors);
};

}
稍微改变了Florian对懒惰者的回答,因为这让ts sonar生气(认知复杂性规则):


要显示自定义错误
nameLengthFive
记住hasrerror是在
FormGroup
上调用的,而不是在
FormControl
上调用的。你的答案是正确的,很容易被忽略。你传递的函数命名错误(应该是
atlestone
,而不是
atlestoneof
const isFieldEmpty = (fieldName: string, fg: FormGroup) => {
    const field = fg.get(fieldName).value;
    if (typeof field === 'number') { return field && field >= 0 ? true : false; }
    if (typeof field === 'string') { return field && field.length > 0 ? true : false; }
};

export function atLeastOne(...fields: string[]) {
  return (fg: FormGroup): ValidationErrors | null => {
    return fields.some(fieldName => isFieldEmpty(fieldName, fg))
      ? null
      : ({ atLeastOne: 'At least one field has to be provided.' } as ValidationErrors);
  };
}