You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular中如何将textarea输入转为数组?表单提交数组变字符串问题

问题

在Angular表单中使用textarea,将string[]作为FormControl的类型。在ngModelChange事件中提取输入的邮箱地址并赋值给数组,但提交表单时数组却被转为字符串值,请问这种实现方式是否正确?

相关代码:

public emailList: string[] = [];
public form: FormGroup = new FormGroup({});

public ngOnInit(): void {
  this.form = new FormGroup({
    sendMeACopy: new FormControl(false, []),
    emailAddressesGroup: new FormControl(this.emailList, [
      Validators.pattern(/^([\w+-.%]+@[\w-.]+\.[A-Za-z]{2,4},?\s?)+$/),
    ]),
  });
}

public extractEmailList(e: any): void {
  this.emailList = [];
  if (this.generateMonthlyProductionReportForm.valid) {
    let emails = e.replace(/\s/g, "").split(",");
    emails.forEach((email: any) => {
      if (email && email.length > 0) {
        this.emailList.push(email);
      }
    });
  }
}

public report() {
  if (this.form.invalid) {
    for (const control of Object.keys(
      this.form.controls
    )) {
      this.form.controls[
        control
      ].markAsTouched();
    }
    return;
  }
  console.log(this.form.value);
}
<form [formGroup]="form">
  <div class="container">
    <div>
      <div>Recipient</div>
      <div>
        <ejs-checkbox
          formControlName="sendMeACopy"
          name="send me a copy"
          label="Send me a copy"
        >
        </ejs-checkbox>
      </div>
      <div>
        <textarea
          (ngModelChange)="extractEmailList($event)"
          formControlName="emailAddressesGroup"
          id="emailAddresses"
          name="Email Address Input"
          placeholder="Use a comma to separate email addresses."
        ></textarea>
        <div
          *ngIf="
            form.controls[
              'emailAddressesGroup'
            ].hasError('pattern') &&
            form.controls[
              'emailAddressesGroup'
            ].dirty
          "
          class="e-error"
        >
          Please enter comma separated list of valid email addresses.
        </div>
      </div>
    </div>
  </div>
  
  <button
        (click)="report()"
        class="btn btn-primary"
        [disabled]="!form.valid"
        type="button"
      >
        Submit
      </button>
</form>

表单提交输出:

  • 初始状态:
{"emailAddressesGroup": [], "sendMeACopy": false}
  • 输入值后:
{"emailAddressesGroup": "asds@sfg.gh, sdf@sfdf.hj", "sendMeACopy": false}

问题分析与解决方案

你的实现方式存在核心问题,同时还有几处细节错误:

  1. 表单变量引用错误:extractEmailList里用了不存在的generateMonthlyProductionReportForm,实际应该用this.form,导致邮箱解析逻辑从未执行。
  2. 控件值未同步:textarea的输入本质是字符串,FormControl会自动同步这个字符串到控件值中,你只更新了emailList变量,但没有修改FormControl的实际值,所以提交时还是原始字符串。
  3. 校验逻辑与存储类型不匹配:你用校验字符串的正则来校验数组类型的控件值,逻辑上不兼容。

修正方案(两种可选)

方案1:保持控件存字符串,提交时转数组(推荐,贴合textarea特性)

这种方式最简单,利用textarea原生的字符串输入,提交时再解析为数组,保留原有校验逻辑:

public emailList: string[] = [];
public form: FormGroup = new FormGroup({});

public ngOnInit(): void {
  this.form = new FormGroup({
    sendMeACopy: new FormControl(false, []),
    emailAddressesGroup: new FormControl('', [
      Validators.pattern(/^([\w+-.%]+@[\w-.]+\.[A-Za-z]{2,4},?\s?)+$/),
    ]),
  });
}

// 实时解析邮箱列表(可选,用于展示或其他逻辑)
public extractEmailList(e: string): void {
  this.emailList = [];
  if (e) {
    const emails = e.replace(/\s/g, "").split(",");
    this.emailList = emails.filter(email => email.trim().length > 0);
  }
}

public report() {
  if (this.form.invalid) {
    Object.values(this.form.controls).forEach(control => control.markAsTouched());
    return;
  }
  // 提交时将字符串转为数组
  const submitValue = {
    ...this.form.value,
    emailAddressesGroup: this.emailList
  };
  console.log(submitValue);
}

方案2:让控件直接存储数组(自定义同步逻辑)

如果需要表单生命周期内始终操作数组,可手动同步控件值,并调整校验逻辑:

public emailList: string[] = [];
public form: FormGroup = new FormGroup({});

public ngOnInit(): void {
  this.form = new FormGroup({
    sendMeACopy: new FormControl(false, []),
    emailAddressesGroup: new FormControl([], [
      // 自定义校验:检查数组中每个邮箱是否合法
      (control) => {
        const emails = control.value as string[];
        const emailRegex = /^[\w+-.%]+@[\w-.]+\.[A-Za-z]{2,4}$/;
        const invalidEmails = emails.filter(email => !emailRegex.test(email));
        return invalidEmails.length > 0 ? { invalidEmails: true } : null;
      }
    ]),
  });
}

public extractEmailList(e: string): void {
  this.emailList = [];
  if (e) {
    const emails = e.replace(/\s/g, "").split(",");
    this.emailList = emails.filter(email => email.trim().length > 0);
  }
  // 同步更新FormControl的值为数组
  this.form.get('emailAddressesGroup')?.setValue(this.emailList);
}

public report() {
  if (this.form.invalid) {
    Object.values(this.form.controls).forEach(control => control.markAsTouched());
    return;
  }
  console.log(this.form.value);
}

对应HTML调整错误提示(方案2用):

<div
  *ngIf="
    form.controls['emailAddressesGroup'].hasError('invalidEmails') &&
    form.controls['emailAddressesGroup'].dirty
  "
  class="e-error"
>
  请输入有效的邮箱地址,用逗号分隔。
</div>

内容的提问来源于stack exchange,提问作者tangel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 08:45:35