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

Angular15+ngx-quill v21.0.0结合FormBuilder无法获取编辑器值

解决Angular 15 + ngx-quill v21.0.0表单绑定无法获取编辑器值的问题

问题现象

使用FormBuilder创建表单并绑定ngx-quill编辑器后,出现以下异常:

  • 编辑器输入内容后,content表单控件值始终为null
  • controls.content.errors.required持续为true
  • controls.content.touched始终为false

解决方案

1. 修正表单控件初始值

将content控件的初始值从null改为空字符串''。ngx-quill与表单控件绑定时,初始null会导致值更新逻辑无法正常触发,同时required验证规则对null会直接判定不通过:

// 在ngOnInit中修改表单构建代码
this.blogForm = this.fb.group({
  title: ['', Validators.required],
  content: ['', Validators.required], // 替换null为''
});

2. 确保QuillModule正确导入

在当前组件所属模块(如AppModule)中导入QuillModule并调用forRoot(),这是ngx-quill集成Angular表单的必要配置:

import { QuillModule } from 'ngx-quill';

@NgModule({
  imports: [
    // ...其他模块导入
    QuillModule.forRoot()
  ]
})
export class YourModule { }

3. 移除自定义Enter键盘绑定

你配置的keyboard.bindings.enter会阻断Quill的默认输入行为,导致编辑器内容变化无法同步到表单控件。直接删除该绑定配置:

// 修改quillConfig中的keyboard配置
keyboard: {
  bindings: {
    // 移除以下enter绑定代码
    // enter: {
    //   key: 13,
    //   handler: (range: any, context: any) => {
    //     console.log('enter');
    //     return true;
    //   },
    // },
  },
},

4. 手动标记控件为touched(可选)

如果编辑器的blur事件未正确触发控件的touched状态,在onBlur方法中手动设置:

// 在组件类中添加onBlur方法
onBlur() {
  this.blogForm.get('content')?.markAsTouched();
}

5. 验证依赖版本兼容性

确认package.json中依赖版本匹配:

  • Angular 15 与 ngx-quill v21.x版本兼容
  • 确保quill版本符合ngx-quill v21.x的要求(通常为v1.3.7+)

调整后的代码参考

editor.component.ts

quillConfig = {
  toolbar: {
    container: [
      ['bold', 'italic', 'underline', 'strike'],
      ['code-block'],
      [{ header: 1 }, { header: 2 }],
      [{ list: 'ordered' }, { list: 'bullet' }],
      ['clean'],
      ['link'],
    ],
  },
  mention: {
    allowedChars: /^[A-Za-z\sÅÄÖåäö]*$/,
    mentionDenotationChars: ['@', '#'],
    source: (
      searchTerm: string,
      renderList: (arg0: any[], arg1: any) => void,
      mentionChar: string
    ) => {
      let values;
      if (mentionChar === '@') {
        values = this.atValues;
      } else {
        values = this.hashValues;
      }
      if (searchTerm.length === 0) {
        renderList(values, searchTerm);
      } else {
        const matches = [];
        for (var i = 0; i < values.length; i++)
          if (
            ~values[i].value.toLowerCase().indexOf(searchTerm.toLowerCase())
          )
            matches.push(values[i]);
        renderList(matches, searchTerm);
      }
    },
  },
  'emoji-toolbar': true,
  'emoji-textarea': false,
  'emoji-shortname': true,
  keyboard: {
    bindings: {
      // 已移除enter绑定
    },
  },
};

constructor(private fb: FormBuilder) {}

ngOnInit(): void {
  this.blogForm = this.fb.group({
    title: ['', Validators.required],
    content: ['', Validators.required], // 修正初始值
  });
}

onSubmit() {
  console.log(this.blogForm.value);
  console.log(this.blogForm);
}

onBlur() {
  this.blogForm.get('content')?.markAsTouched(); // 手动标记touched
}

editor.component.html

<div class="tt-form-container">
  <form class="tt-blogForm" [formGroup]="blogForm" (ngSubmit)="onSubmit()">
    <h2>Write a Blog</h2>
    <div>
      <label for="title"> Title:</label>
      <input type="text" id="title" formControlName="title" />
    </div>
    <div>
      <label for="content">Content:</label>
      <quill-editor
        class="tt-blog-editor"
        theme="snow"
        formControlName="content"
        [modules]="quillConfig"
        (onBlur)="onBlur()"
      >
      </quill-editor>
    </div>
    <div>
      <button class="tt-blog-button" type="submit">Submit</button>
    </div>
  </form>
</div>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 08:08:09