Listen to text changes of an existing state/view

I found a couple of old discussions regarding v6 equivalents of onChange, but they all start from a fresh editor:

let state = EditorState.create({
    extensions: [updateListenerExtension]
});

Is there a way to attach a listener to an existing item on the page? I need to do this from an extension so I want to make sure I don’t break the 3rd-party editor by recreating the whole state.

I’m testing the following code on https://codemirror.net

const cmView = document.querySelector('.cm-content').cmView;
const EditorView = cmView.view.constructor;
const updateListenerExtension = EditorView.updateListener.of((v) => {
    console.log(v.state.doc.toString());
});

cmView.view.state./*TODO: .addExtension(updateListenerExtension) */

There is a way to attach extensions, but for that you do need access to the StateEffect.appendConfig value that the codemirror instance you want to listen to uses. The way codemirror/javascript works now, there is no way to do that…

It isn’t pretty, but your GhostText PR works if I do

sendBack(target, cmView.view.state.doc.toString());
let last_doc = cmView.view.state.doc;

setInterval(() => {
	if (last_doc !== cmView.view.state.doc) {
		sendBack(target, cmView.view.state.doc.toString());
		last_doc = cmView.view.state.doc;
	}
}, 100);

target.addEventListener("gt:transfer", () => {
	cmView.view.dispatch({
		changes: {
			from: 0,
			to: cmView.view.state.doc.length,
			insert: target.getAttribute("gt-value"),
		},
	});
	last_doc = cmView.view.state.doc;
});

You could also use cmView.addEventListener("input", () => ...), but I feel like that will miss cases where extensions change text based on shortcuts.

and I think setInterval is really the only way to make this work reliably :confused:

Thank you! I suppose this is a start to move things along in my PR. I’m thinking about using the input event to track keypresses and then use the polling to complement that and update the field twice per second.

I hope a helper for this will be implemented in CM6 however

Let’s continue this discussion in this thread.