-
Notifications
You must be signed in to change notification settings - Fork 6
Description
Bug
CodeEditor.setValue() dispatches document changes without the External annotation, causing the component's _updateListener to treat programmatic writes as user edits.
Impact
When Angular Forms calls writeValue() during initialization (e.g., when a form control is bound with [(ngModel)]), the flow is:
writeValue()→setValue(value)setValue()dispatchesview.dispatch({ changes, annotations: [Transaction.addToHistory.of(false)] })_updateListenerseesdocChanged && !tr.annotation(External)→ calls_onChange()- Angular marks the form control as dirty even though no user edit occurred
This causes forms containing <code-editor> to show false unsaved-changes state on load.
Root Cause
In code-editor.ts, setValue() includes Transaction.addToHistory.of(false) but does not include External.of(true):
setValue(value: string) {
this.view.dispatch({
changes: { from: 0, to: this.view.state.doc.length, insert: value },
annotations: Transaction.addToHistory.of(false),
});
}The _updateListener already has the correct guard:
if (update.docChanged && !update.transactions.some(tr => tr.annotation(External))) {
// calls _onChange
}The mechanism exists and works — setValue() simply doesn't use it.
Fix
Add External.of(true) to the annotations array in setValue():
setValue(value: string) {
this.view.dispatch({
changes: { from: 0, to: this.view.state.doc.length, insert: value },
annotations: [Transaction.addToHistory.of(false), External.of(true)],
});
}Workaround
We are currently monkey-patching CodeEditor.prototype.setValue to add the annotation:
CodeEditor.prototype.setValue = function(value: string) {
if (!this.view) return;
this.view.dispatch({
changes: { from: 0, to: this.view.state.doc.length, insert: value },
annotations: [Transaction.addToHistory.of(false), External.of(true)],
});
};Version
@acrodata/code-editor@0.6.0