I could not figure out which API(s) in view/state to listen on state.doc change.
I think this is the closest equivalent to CM5’s change event:
let updateListenerExtension = EditorView.updateListener.of((update) => {
if (update.docChanged) {
// Handle the event here
}
});
let state = EditorState.create({
extensions: [updateListenerExtension/* Add your other extensions */]
});
Is there a way to add a listener to already existing state?
Without importing global variables EditorView
and EditorState
, which might be from a different version package. And without creating a new state, because the existing state might have a number of extensions attached.
Something like this:
const dispatch = editor.dispatch;
editor.dispatch = (...args: any[]) => {
console.log('update xxx');
return dispatch.apply(editor, args);
};
I ended with something like this:
private _d?: (...args: any[]) => unknown;
constructor(protected readonly editor: EditorView) {
this._d = editor.dispatch;
Object.defineProperty(editor, 'dispatch', {
...Object.getOwnPropertyDescriptor(editor, 'dispatch'),
value: (...args: any[]) => {
const res = this._d!.apply(editor, args);
this.onchange?.();
return res;
},
});
}
public dispose(): void {
if (this._d) {
Object.defineProperty(this.editor, 'dispatch', {
...Object.getOwnPropertyDescriptor(this.editor, 'dispatch'),
value: this._d,
});
}
}
let view = new EditorView({
doc: “//Type here\na=10; \n b”,
extensions: [
basicSetup,
errorMarkerExtn(),
EditorView.updateListener.of((update) => {
if (
update.docChanged &&
!update.changes.some((change) => change.isUser)
) {
// Ignore changes that are not user-initiated (e.g., programmatic)
return;
}
// update.state.doc
holds the current document content
console.log("Editor content updated:", update.state.doc.toString());
// Perform your desired actions based on the updated content
}),
],
parent: document.body,
});