create(elem: HTMLElement) {
if (!elem) return;
const customTheme = EditorView.theme({
".cm-content": {
fontFamily: "var(--bs-body-font-family) !important"
}
});
let state = EditorState.create({
doc: "",
extensions: [
keymap.of([...defaultKeymap, indentWithTab]),
bracketMatching(),
closeBrackets(),
customTheme
]
});
let view = new EditorView({
state,
parent: elem
});
}
create(document.getElementById("foo-container") as HTMLElement);
create(document.getElementById("bar-container") as HTMLElement);
Now, I need to change its value(displayed so) by HTMLElement id, such as:
function updateElementFromData(element: HTMLElement, value: string): void {
console.log(element); // this will print the html element foo or bar
// here's the logic to update code mirror value by element
}
Is it possible? How can I do it? Of course updateElementFromData must be agnostic, and retrieve the object by HTMLElement.
Such as if the HTMLElement was an instanceof of HTMLTextAreaElement, I can easily do:
The EditorView.findFromDOM static method may be useful for getting an EditorView instance from a DOM element. To set a new document, you want to create a new EditorState and use EditorView.setState.
@marijn wow, what a serious tool. Seems to works like a charm:
let customTextArea = EditorView.findFromDOM(element);
if (customTextArea) {
const state = CustomTextArea.createState(value.toString());
customTextArea.setState(state);
}
Since it seems I can’t change the actual .doc variable, I’ve created the helper createState (which has default state for every object). Thanks.
Now: how can I do the opposite? I mean, from an HTMLElement element:
understand if that’s an instance of EditorView
if its, attach an addEventListener, so any edits of that “doc”, will trigger a specific function?
You could dispatch a reconfiguration transaction, but in general, the preferred style for CodeMirror is to configure the state when creating it, rather than via imperative updates.
I got what’s the problem. IS because on other part I’ve the first part of code:
let customTextArea = EditorView.findFromDOM(element);
if (customTextArea) {
const state = CustomTextArea.createState(value.toString());
customTextArea.setState(state);
}
which run later and override the previous update handler
SO: how can I update the “doc” text when change, instead of create a new EditorState and set it? (which is basically HUGE in terms of performances, since it will override template, indent, and N params).
I believe there is somethings straightforward to update doc programmatically?
@marijn ok, I start to see what are the problems with history.
Here’s my actual updateContent function, which programmatically change the text of CodeMirror (useful because I’m using it on a DataBind to a my custom JS object):
static updateContent(view: EditorView, value: string) {
view.dispatch({
changes: {
from: 0,
to: view.state.doc.length,
insert: value
},
selection: EditorSelection.cursor(Math.min(view.state.selection.main.head, value.length)), // preserve cursor after change content
annotations: CustomTextArea.annotationDataBind.of(true) // prevent infinite loop when set value on DataBind (avoid to trigger updateListener)
});
}
view.dispatch({
changes: {
from: 0,
to: view.state.doc.length,
insert: value
},
selection: EditorSelection.cursor(Math.min(view.state.selection.main.head, value.length)), // preserve cursor after change content
annotations: CustomTextArea.annotationDataBind.of(true) // prevent infinite loop when set value on DataBind (avoid to trigger updateListener)
});
which update the value, nothing more. But it preserve only the last change. So history (ctrl+z) just restore a single undo.
i.e. if I wrote text, and do a new line, with ctrl+z I can just restore One/unique single undo (not as many as I Need as for usual text box pressing many ctrl+z).
If you do this closer than half a second together, the changes (since they overlap—because you replace the entire document) will be combined into a single event, and you’ll undo them all at once. If that’s not it, I don’t know what the issue is.
Try write some text, wait also seconds between every hits, and than undo… undo… undo… only the first will work.
Basically I need an external “watcher” which will be handled on change, thus update a linked “member” variable of an object: so sync the change between che CodeMirror and my own custom object on change.
I guess this is the way on doing this? But not sure why I’m loosing the history
What appears to be happening is that your redoing of every change (with a full content replace) keeps re-adding an event to the undo history whenever you’re trying to undo, so that the next undo just undoes that (useless) replace.