For a text-only maintenance notice, <p><br></p> should fail the same rule as an empty field. A notice saying “The north entrance closes at 6 p.m.” should pass. Those are application requirements; a nonempty HTML string alone cannot distinguish them.
Start with the Angular integration you can support
Use ckeditor5 with @ckeditor/ckeditor5-angular in an existing Angular project. Match the versions against the official compatibility table, rather than mixing an old custom build with a new wrapper. The self-hosted setup also needs the editor stylesheet and a license configuration that fits your distribution. CKEditor's Angular installation instructions describe those requirements.
For a standalone component, include FormsModule and CKEditorModule in the component's imports. Configure its Editor constructor and plugins before using this template fragment:
<form #noticeForm="ngForm" (ngSubmit)="captureNotice()">
<p id="notice-label">Maintenance notice</p>
<ckeditor
[editor]="Editor"
[config]="config"
[(ngModel)]="noticeHtml"
name="notice"
required
#notice="ngModel">
</ckeditor>
@if (notice.invalid && (notice.dirty || notice.touched)) {
<p>Enter the maintenance notice.</p>
}
<button type="submit" [disabled]="noticeForm.invalid">
Check notice
</button>
</form>
The wrapper implements Angular's ControlValueAccessor. Its binding connects editor changes to noticeHtml; the name registers that control with the form. Angular's template-driven form guide explains the imports, control names, and ngSubmit behavior.
Configure an accessible editor label through the editor's supported accessibility options for your chosen build. A nearby paragraph is explanatory text; it does not by itself give the editing region a programmatic name.
Add the rule your notice actually needs
required checks the form value. A rich text value can still contain tags or spaces without useful words. In a browser-side component, this bounded check treats the notice as text:
noticeHtml = '<p>The north entrance closes at 6 p.m.</p>';
noticeError = '';
capturedHtml = '';
captureNotice(): void {
const doc = new DOMParser().parseFromString(this.noticeHtml, 'text/html');
const words = (doc.body.textContent ?? '').replace(/\u00a0/g, ' ').trim();
if (!words) {
this.noticeError = 'Enter the maintenance notice before continuing.';
return;
}
this.noticeError = '';
this.capturedHtml = this.noticeHtml;
}
Display noticeError beside the control. This example only captures a value in component memory. Your existing save service must still validate, authorize, and persist it, then report whether that save succeeded.
The text check suits a notice that must contain words. An image-only article or embedded diagram needs a different content rule. Parsing HTML for text is also separate from sanitizing stored HTML for later display.
For feedback while typing, move the content rule into an Angular validator instead of checking only on submit. Angular's validation documentation covers custom validators and when to display errors.
Test the value at the form boundary
Use these three inputs before connecting the save endpoint:
| Editor content | Expected notice decision |
|---|---|
| Empty editor or a blank paragraph | Reject; keep the editor available for correction |
| Spaces or nonbreaking spaces only | Reject under this text-only rule |
| A paragraph with the entrance notice | Capture the current HTML, including supported formatting |
Then change “north” to “east” and capture again. Read the captured value rather than assuming the visible editor proves the binding worked. If the old word remains, inspect ngModel, the control name, and any code that replaces noticeHtml after loading.
Avoid repeatedly resetting the editor from an API response while someone types. Load a document deliberately, then let the form own its editing value. Large documents also need a deliberate choice about continuous data binding; the CKEditor integration documents an option to disable it and read data on demand.
The single-file Angular introduction covers basic template bindings. This form uses a built Angular project and a separate editor document. Finish by reopening the saved notice through your actual application and checking that the corrected entrance and closing time both survived.