I am currently working with an angular component that incorporates a rich text editor (tiptap v2) and displays the corresponding JSON output. I have created an observable from the update
event provided by the editor, aiming to initialize the editor with mock data. My expectation was for the editor to trigger an update event, leading to the correct display of JSON data. However, this does not work after initialization, as the async pipe returns null. Although I found a workaround using the rxjs startWith
operator, it feels odd to initialize the observable separately from the editor it should observe.
Below is my template:
<div class="editor-window">
<tiptap-editor [editor]="editor"></tiptap-editor>
</div>
<div style="margin-top: 15px">
<b>JSON</b><br />
<pre style="overflow: scroll">{{ editorJson$ | async | json }}</pre>
<mat-divider></mat-divider>
</div>
Additionally, here is the corresponding component setup:
import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
import { Editor } from '@tiptap/core';
import { StarterKit } from '@tiptap/starter-kit';
import { fromEvent, Observable, startWith } from 'rxjs';
import { dummyContent } from './dummy-content';
@Component({
selector: 'nai-annotation-editor',
templateUrl: './annotation-editor.component.html',
styleUrls: ['./annotation-editor.component.scss'],
encapsulation: ViewEncapsulation.None,
})
export class AnnotationEditorComponent implements OnInit, OnDestroy {
public editor: Editor;
// Register editor 'update event' as observable
public editorJson$: Observable<any> | undefined;
constructor() {
this.editor = new Editor({
extensions: [
StarterKit.configure({
heading: {
levels: [1, 2, 3],
},
blockquote: false,
code: false,
codeBlock: false,
horizontalRule: false,
strike: false,
}),
],
});
}
ngOnInit(): void {
this.editorJson$ = fromEvent(this.editor, 'update', (event) =>
event?.editor.getJSON()
); //.pipe(startWith(dummyContent));
this.editor.commands.setContent(dummyContent, true);
}
ngOnDestroy(): void {
this.editor.destroy();
}
}
Moving the editor.commands.setContent(...)
to ngAfterViewInit()
results in the expected display, but triggers an
ExpressionChangedAfterItHasBeenChecked
Error.
Despite confirming that the observable indeed returns a value through subscription and console.log output, why is it not being displayed by the async pipe?
My suspicion falls on the component lifecycle and usage of the async pipe, but I lack certainty...