|
options
|
Type : any
|
Default value : {}
|
|
|
|
insideNg
|
Type : boolean
|
Default value : false
|
|
|
|
|
Methods
|
registerOnChange
|
registerOnChange(fn: any)
|
|
|
Parameters :
| Name |
Type |
Optional |
| fn |
any
|
No
|
|
|
registerOnTouched
|
registerOnTouched(fn: any)
|
|
|
Parameters :
| Name |
Type |
Optional |
| fn |
any
|
No
|
|
|
setDisabledState
|
setDisabledState(disabled: boolean)
|
|
|
Parameters :
| Name |
Type |
Optional |
| disabled |
boolean
|
No
|
|
|
writeValue
|
writeValue(value: any)
|
|
|
Parameters :
| Name |
Type |
Optional |
| value |
any
|
No
|
|
|
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')
|
|
|
|
|
|
config
|
Type : unknown
|
Default value : inject<NgxMonacoEditorConfig>(NGX_MONACO_EDITOR_CONFIG)
|
|
|
|
|
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 with directive