Angular6集成Quill.js遇Quill未定义错误的技术问询
Let's break down the two key issues you're facing and walk through the fixes step by step:
1. Quill Can't Attach to a <textarea> Element
First off, Quill.js doesn't work with <textarea> elements directly. It replaces the target DOM element with its own rich editor structure, so you need to swap your <textarea> for a <div> container. Since we can't use formControlName directly on a div, we'll manually sync the editor content with your form control.
Update your template to use a div (and add a template reference for easier access in your component):
<div #questionDescription class="form-control" [ngClass]="validateField('questionDescription')"></div>
2. Quill Isn't Being Loaded by Angular's Build System
Your declare var Quill: any; tells TypeScript that Quill exists, but Angular's bundler isn't actually loading Quill's JavaScript and CSS into the browser. You have two solid options to fix this:
Option 1: Add Quill to angular.json (Global Load)
Open your angular.json file, find the architect > build > options section, and add Quill's CSS and JS to the styles and scripts arrays:
"styles": [ "src/styles.css", "node_modules/quill/dist/quill.snow.css" ], "scripts": [ "node_modules/quill/dist/quill.js" ]
This loads Quill globally across your app.
Option 2: Import Quill Directly in Your Component (Tree-Shaking Friendly)
This is the cleaner approach for component-specific usage. Remove the declare var Quill: any; line, then import Quill and its CSS directly in your component:
import Quill from 'quill'; import 'quill/dist/quill.snow.css';
Angular will bundle only what's needed for this component.
Full Working Example
Here's how to tie it all together with form sync:
Component TypeScript
import { Component, AfterViewInit, ViewChild, ElementRef } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; import Quill from 'quill'; import 'quill/dist/quill.snow.css'; @Component({ selector: 'app-new-practice-question', templateUrl: './new-practice-question.component.html', styleUrls: ['./new-practice-question.component.css'] }) export class NewPracticeQuestionComponent implements AfterViewInit { practiceQuestionForm = new FormGroup({ questionDescription: new FormControl('', Validators.required) }); @ViewChild('questionDescription') quillContainer!: ElementRef; private quillInstance!: Quill; ngAfterViewInit(): void { // Initialize Quill editor this.quillInstance = new Quill(this.quillContainer.nativeElement, { theme: 'snow' }); // Sync initial form value to the editor const initialValue = this.practiceQuestionForm.get('questionDescription')?.value; if (initialValue) { this.quillInstance.root.innerHTML = initialValue; } // Sync editor changes back to the form control this.quillInstance.on('text-change', () => { this.practiceQuestionForm.get('questionDescription')?.setValue(this.quillInstance.root.innerHTML); }); } validateField(fieldName: string) { const field = this.practiceQuestionForm.get(fieldName); return { 'is-invalid': field?.invalid && (field.dirty || field.touched) }; } }
Component Template
<form [formGroup]="practiceQuestionForm"> <div #questionDescription class="form-control" [ngClass]="validateField('questionDescription')"></div> <!-- Show validation error if needed --> <div *ngIf="practiceQuestionForm.get('questionDescription')?.invalid && (practiceQuestionForm.get('questionDescription')?.dirty || practiceQuestionForm.get('questionDescription')?.touched)" class="invalid-feedback"> Question description is required. </div> </form>
Key Takeaways
- Always use a
<div>(not<textarea>) as the Quill container - Ensure Quill's JS and CSS are properly loaded either via
angular.jsonor component imports - Manually sync Quill content with your Angular form control using the editor's
text-changeevent
内容的提问来源于stack exchange,提问作者Manu Chadha

