atularen / ngx-monaco-editor

Monaco Editor component for Angular 2 and Above
https://www.npmjs.com/package/ngx-monaco-editor
MIT License
428 stars 155 forks source link

reactive forms: form asynchronously reemits new value #101

Open j2L4e opened 5 years ago

j2L4e commented 5 years ago

say you attach a formcontrol to the editor component:

const form = new FormControl('asd');
<ngx-monaco-editor [options]="editorOptions" [formControl]="form">
<pre>isPristine: {{ form.pristine }}</pre>

Now you set the formControl's value and after that mark it as pristine:

this.form.setValue('new value');
this.form.markAsPristine();

I'd expect the form to be pristine now, while in fact it's marked dirty, because the value is reemitted asynchronously. (Technically it was marked pristine, but it's marked dirty again shortly after. Likely on the next tick.)

The editor component should reemit a newly set value synchronously, pass the value to the editor and pause value emission, swallow the asynchronously emitted value and then resume emission.

Workaround:

I work around this by wrapping ngx-monaco-editor and proxy the ControlValueAccessor

export class MyWrapperComponent implements ControlValueAccessor {
  @ViewChild(EditorComponent) editorComponent: EditorComponent;

  private _justSetValue: any;
  private _onChange: any;

  registerOnChange (fn: any): void {
    this._onChange = fn;

    this.editorComponent.registerOnChange((val: any) => {
      // skip value if it is the just set value. relevant values are strings and `null`, so `===` is ok.
      if(this._justSetValue === val) {
        this._justSetValue = undefined;
        return;
      }

      fn(val);
    });
  }

  registerOnTouched (fn: any): void {
    this.editorComponent.registerOnTouched(fn);
  }

  writeValue (val: any): void {
    if(this._onChange) {
      this._onChange(val);
      this._justSetValue = val;
    }
    this.editorComponent.writeValue(val);
  }
}
altso commented 4 years ago

I am facing the same issue. Would love to see it fixed.

fwitkowski commented 3 years ago

In my case I needed set this to pristine, when resetting the form to initial state. Same issue as above. My workaround was to re-initialize the monaco editor (running onItin funtion). For me it was easy, because my monaco editor is as optional field (inside accordion), so I just wrapped editor inside *ngIf directive and set it to false and back to true. There is one link here, how to re-initialize the editor: https://stackoverflow.com/questions/62465694/how-to-clear-existing-models-or-is-there-a-way-to-re-init-monaco-editor However, I haven't try it.

beezital commented 3 years ago

same issue here +1