libs/core/monaco-editor/src/lib/monaco-editor/editor.component.ts

Extends

BaseEditor

Implements

ControlValueAccessor

Metadata

Relationships

Index

Properties
Methods
Inputs
Outputs

Constructor

constructor()

Inputs

model
Type : NgxEditorModel | undefined
Default value : undefined
options
Type : any
Default value : {}
insideNg
Type : boolean
Default value : false
Inherited from BaseEditor

Outputs

onInit
Type : any
Inherited from BaseEditor

Methods

registerOnChange
registerOnChange(fn: any)
Parameters :
Name Type Optional
fn any No
Returns : void
registerOnTouched
registerOnTouched(fn: any)
Parameters :
Name Type Optional
fn any No
Returns : void
setDisabledState
setDisabledState(disabled: boolean)
Parameters :
Name Type Optional
disabled boolean No
Returns : void
writeValue
writeValue(value: any)
Parameters :
Name Type Optional
value any No
Returns : void

Properties

onTouched
Type : unknown
Default value : () => {...}
Readonly options
Type : unknown
Default value : computed(() => Object.assign({}, this.config.defaultOptions, this.optionsInput()) )
propagateChange
Type : unknown
Default value : () => {...}
Readonly _editorContainer
Type : unknown
Default value : viewChild.required<ElementRef>('editorContainer')
Inherited from BaseEditor
config
Type : unknown
Default value : inject<NgxMonacoEditorConfig>(NGX_MONACO_EDITOR_CONFIG)
Inherited from BaseEditor
import {
  ChangeDetectionStrategy,
  Component,
  NgZone,
  computed,
  effect,
  forwardRef,
  inject,
  input,
  untracked
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { fromEvent } from 'rxjs';

import { BaseEditor } from './base-editor';
import { NgxEditorModel } from './types';

declare let monaco: any;

@Component({
  standalone: true,
  selector: 'taly-monaco-editor',
  template: '<div class="editor-container" #editorContainer></div>',
  styles: [
    `
      :host {
        display: block;
        height: 200px;
      }

      .editor-container {
        width: 100%;
        height: 98%;
      }
    `
  ],
  changeDetection: ChangeDetectionStrategy.OnPush,
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => EditorComponent),
      multi: true
    }
  ]
})
export class EditorComponent extends BaseEditor implements ControlValueAccessor {
  private zone = inject(NgZone);
  private _value = '';
  private disabledOverride = false;
  private themeOverride: string | undefined;

  // eslint-disable-next-line @angular-eslint/no-input-rename
  readonly optionsInput = input<any>({}, { alias: 'options' });

  readonly options = computed(() =>
    Object.assign({}, this.config.defaultOptions, this.optionsInput())
  );
  readonly model = input<NgxEditorModel | undefined>(undefined);

  propagateChange = (_: any) => {
    /* empty */
  };
  onTouched = () => {
    /* empty */
  };

  constructor() {
    super();
    effect((onCleanup) => {
      this._options = { ...this.options() };
      if (this.disabledOverride) {
        this._options.readOnly = true;
      }
      if (this.themeOverride) {
        this._options.theme = this.themeOverride;
      }
      const model = this.model();
      if (model) {
        this._options.model = model;
      }
      const insideNg = this.insideNg();
      const monacoLoaded = this.monacoLoaded();
      untracked(() => {
        if (!monacoLoaded) {
          return;
        }
        // `cancelled` guards against the effect re-running (stale options) or the
        // component being destroyed before this microtask gets a turn.
        let cancelled = false;
        onCleanup(() => {
          cancelled = true;
        });
        // Deferred: initMonaco() emits `onInit`, which can trigger change detection —
        // doing that synchronously inside this effect risks NG0100.
        queueMicrotask(() => {
          if (cancelled) {
            return;
          }
          if (this._editor) {
            this._editor.dispose();
          }
          this.initMonaco(this._options, insideNg);
        });
      });
    });
  }

  writeValue(value: any): void {
    this._value = value || '';
    // Fix for value change while dispose in process.
    setTimeout(() => {
      if (this._editor && !this._options.model) {
        this._editor.setValue(this._value);
      }
    });
  }

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

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

  setDisabledState(disabled: boolean): void {
    this.disabledOverride = disabled;
    this._options.readOnly = this.disabledOverride || this.options().readOnly;
  }

  protected initMonaco(options: any, insideNg: boolean): void {
    const hasModel = !!options.model;

    if (hasModel) {
      const model = monaco.editor.getModel(options.model.uri || '');
      if (model) {
        options.model = model;
        options.model.setValue(this._value);
      } else {
        options.model = monaco.editor.createModel(
          options.model.value,
          options.model.language,
          options.model.uri
        );
      }
    }

    if (insideNg) {
      this._editor = monaco.editor.create(this._editorContainer().nativeElement, options);
    } else {
      this.zone.runOutsideAngular(() => {
        this._editor = monaco.editor.create(this._editorContainer().nativeElement, options);
      });
    }

    if (!hasModel) {
      this._editor.setValue(this._value);
    }

    this._editor.onDidChangeModelContent((e: any) => {
      const value = this._editor.getValue();

      // value is not propagated to parent when executing outside zone.
      this.zone.run(() => {
        this.propagateChange(value);
        this._value = value;
      });
    });

    this._editor.onDidBlurEditorWidget(() => {
      this.onTouched();
    });

    this._editor.setTheme = (themeName: string): void => {
      this.themeOverride = themeName;
      this._options.theme = themeName;
      monaco.editor.setTheme(themeName);
    };

    // refresh layout on resize event.
    if (this._windowResizeSubscription) {
      this._windowResizeSubscription.unsubscribe();
    }
    this._windowResizeSubscription = fromEvent(window, 'resize').subscribe(() =>
      this._editor.layout()
    );
    this.onInit.emit(this._editor);
  }
}

      :host {
        display: block;
        height: 200px;
      }

      .editor-container {
        width: 100%;
        height: 98%;
      }
    
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""