{"id":13808487,"url":"https://github.com/jean-merelis/ngx-monaco-editor","last_synced_at":"2026-02-20T21:15:04.279Z","repository":{"id":232408763,"uuid":"784259750","full_name":"jean-merelis/ngx-monaco-editor","owner":"jean-merelis","description":"Monaco Code Editor for Angular","archived":false,"fork":false,"pushed_at":"2025-02-06T18:58:35.000Z","size":656,"stargazers_count":5,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-08T17:53:10.631Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jean-merelis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"license","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-04-09T13:56:36.000Z","updated_at":"2025-05-24T14:45:25.000Z","dependencies_parsed_at":"2024-05-04T16:33:19.028Z","dependency_job_id":"1baa07a5-6d2b-4a48-aefa-58358bdbf72f","html_url":"https://github.com/jean-merelis/ngx-monaco-editor","commit_stats":{"total_commits":23,"total_committers":3,"mean_commits":7.666666666666667,"dds":"0.17391304347826086","last_synced_commit":"1ebb3360850d4b31601ee2059994eb4eddf9aba1"},"previous_names":["jean-merelis/ngx-monaco-editor"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jean-merelis/ngx-monaco-editor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jean-merelis%2Fngx-monaco-editor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jean-merelis%2Fngx-monaco-editor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jean-merelis%2Fngx-monaco-editor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jean-merelis%2Fngx-monaco-editor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jean-merelis","download_url":"https://codeload.github.com/jean-merelis/ngx-monaco-editor/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jean-merelis%2Fngx-monaco-editor/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29664825,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-20T19:49:36.704Z","status":"ssl_error","status_checked_at":"2026-02-20T19:44:05.372Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T01:01:44.058Z","updated_at":"2026-02-20T21:15:04.262Z","avatar_url":"https://github.com/jean-merelis.png","language":"TypeScript","funding_links":[],"categories":["Third Party Components"],"sub_categories":["Editor Components"],"readme":"# NgxMonacoEditor is a  Monaco Editor Component for Angular.\n\nSupports all the options available in monaco-editor [Monaco Editor Options](https://microsoft.github.io/monaco-editor/typedoc/variables/editor.EditorOptions.html)\n\nWe will try to follow the MAJOR.MINOR versions of Angular to make it easier to identify compatibility. That's why our lib started with version 17 and not 1.\n\n- Angular 17.3 =\u003e v17.3.x\n- Angular 18 =\u003e v18.x.x\n- Angular 19 =\u003e v19.x.x\n\n\n## Setup\n\n### Installation\n\nInstall from npm repository:\n```\nnpm install monaco-editor @jean-merelis/ngx-monaco-editor --save\n ```\n\n### Provide a `MonacoLoader`\n\nYou can use `DefaultMonacoLoader` or create your own loader implementing the `MonacoLoader` interface.\n\n`DefaultMonacoLoader` expects Monaco to be in the 'vs' folder of your domain. Ie. `http://localhost:4200/vs/`\nFor that add the following snipt in `angular.json`\n\n```json\n{\n  \"apps\": [\n    {\n      \"assets\": [\n        { \"glob\": \"**/*\",\n          \"input\": \"node_modules/monaco-editor/min/vs\",\n          \"output\": \"vs\"\n        },\n      ],\n    }\n  ],\n}\n ```\n\nYou can provide your own configuration for `DefaultMonacoLoader`, but don't forget to change angular.json as well.\n```typescript\n// providing your own configuration\nconst monacoLoader = new DefaultMonacoLoader({paths: {vs: 'path/to/vs'}});\n\n@Component({\n  selector: 'app-root',\n  standalone: true,\n  templateUrl: './app.component.html',\n  styleUrl: './app.component.scss',\n  imports: [\n    FormsModule, ReactiveFormsModule,\n    NgxMonacoEditorComponent\n  ],\n  providers: [\n    {provide: NGX_MONACO_LOADER_PROVIDER, useValue: monacoLoader} // \u003c\u003c\u003c\n  ]\n})\nexport class AppComponent {\n}\n```\n\n\n### Global Editor configuration\nYou can provide a global configuration for yours editors.\n\n````typescript\nexport interface NgxMonacoEditorConfig {\n  defaultOptions?: StandaloneEditorConstructionOptions;\n  runInsideNgZone?: boolean\n}\n````\n\n```typescript\n\n@Component({\n  selector: 'app-root',\n  standalone: true,\n  templateUrl: './app.component.html',\n  styleUrl: './app.component.scss',\n  imports: [\n    NgxMonacoEditorComponent\n  ],\n  providers: [\n    {\n      provide: NGX_MONACO_EDITOR_CONFIG,\n      useValue: {\n        runInsideNgZone: false,\n        defaultOptions: {\n          minimap: {enabled: true}\n        }\n      }\n    }\n  ]\n})\nexport class AppComponent {\n}\n```\n\n\n\n### Sample\nInclude NgxMonacoEditorComponent in the `imports` of the component or module where you want to use the editor. (eg: app.module.ts). Add the provide the `MonacoLoader`:\n\n```typescript\nimport {Component} from '@angular/core';\nimport {\n  DefaultMonacoLoader,\n  EditorInitializedEvent,\n  NgxMonacoEditorComponent,\n  NGX_MONACO_LOADER_PROVIDER\n} from \"@jean-merelis/ngx-monaco-editor\";\n\n@Component({\n  selector: 'app-root',\n  standalone: true,\n  templateUrl: './app.component.html',\n  styleUrl: './app.component.scss',\n  imports: [\n    NgxMonacoEditorComponent\n  ],\n  providers: [\n    {provide: NGX_MONACO_LOADER_PROVIDER, useFactory: () =\u003e new DefaultMonacoLoader()}\n  ]\n})\nexport class AppComponent {\n  editorOptions = {theme: 'vs-dark', language: 'javascript'};\n  code: string = 'function helloWorld() {\\nconsole.log(\"Hello world!\");\\n}';\n}\n```\n\n```html\n \u003cngx-monaco-editor [options]=\"editorOptions\" [(ngModel)]=\"code\"\u003e\u003c/ngx-monaco-editor\u003e\n```\n\n\n\n### Events\nThe output event (editorInitialized) emits an EditorInitializedEvent that exposes the editor instance, languages, and worker objects from Monaco API\nwhich can be used to perform custom operations in the editor.\n```html\n\u003cngx-monaco-editor #editor [options]=\"editorOptions\" [(ngModel)]=\"code\"\n                   (editorInitialized)=\"editorInitialized($event)\"\n                   (focus)=\"onFocus()\"\n                   (blur)=\"onBlur()\"\n\u003e\u003c/ngx-monaco-editor\u003e\n\n\u003cbutton type=\"button\" (click)=\"editor.focus()\"\u003eSet focus in the editor\u003c/button\u003e\n```\n\n```typescript\nexport class AppComponent {\n  editorOptions = {theme: 'vs-dark', language: 'typescript'};\n  code: string = \"const helloWorld = () =\u003e 'Hello world';\"\n  events: string[] = [];\n\n  // Object from Monaco API\n  private editor: any;\n  private monaco: any;\n\n  editorInitialized(evt: EditorInitializedEvent) {\n    this.events.push(\"editorInitialized\");\n    this.editor = evt.editor;\n    this.monaco = evt.monaco;\n  }\n\n  onFocus() {\n    this.events.push(\"focus\");\n  }\n\n  onBlur() {\n    this.events.push(\"blur\");\n  }\n}\n```\n\n\n## Testing\n\nWhen testing components that use the Monaco Editor, you have two approaches:\n\n\n### 1. Testing with NgxMonacoEditorHarness (Real Editor)\n\nThis approach uses the actual Monaco Editor in your tests. While it provides complete integration testing, it requires more setup and can make tests slower and more complex due to Monaco Editor's initialization process.\n\n\n#### Testing with NgxMonacoEditorHarness\n\n```typescript\nimport { NgxMonacoEditorHarness, MonacoEditorHarnessFilters } from \"@jean-merelis/ngx-monaco-editor/testing\";\n ```\n\nHarness for interacting with NgxMonacoEditor in tests.\n\nYou may want to run your tests with fakeAsync, so you need to configure to run Monaco Editor inside NgZone.\nThen, in the last line of the test, call the `discardPeriodicTasks()` function\n\nConfigure your test to wait for monacoLoader to complete. See the example below:\n\n```typescript\n\n@Component({\n  selector: 'wrapper',\n  standalone: true,\n  imports: [\n    CommonModule,\n    FormsModule,\n    ReactiveFormsModule,\n    NgxMonacoEditorComponent,\n  ],\n  template: `\n    \u003cngx-monaco-editor [(value)]=\"code\" data-testid=\"editor-1\"\n                       style=\"height: 120px\"\n    \u003e\u003c/ngx-monaco-editor\u003e\n\n    \u003cngx-monaco-editor [(value)]=\"code2\" data-testid=\"editor-2\"\n                       style=\"height: 120px\"\n    \u003e\u003c/ngx-monaco-editor\u003e\n  `\n})\nexport class YourWrapperComponent {\n  code = model(\"\");\n  code2 = model(\"\");\n}\n\ndescribe(\"NgxMonacoEditorComponent\", () =\u003e {\n\n  let fixture: ComponentFixture\u003cYourWrapperComponent\u003e;\n  let loader: HarnessLoader;\n\n  beforeEach(async () =\u003e {\n    await TestBed.configureTestingModule({\n      imports: [\n        YourWrapperComponent,\n        NgxMonacoEditorComponent\n      ],\n      providers: [\n        {provide: NGX_MONACO_LOADER_PROVIDER, useFactory: () =\u003e new DefaultMonacoLoader()},\n\n        // If you need to run your tests with fakeAsync then run inside NgZone\n        {provide: NGX_MONACO_EDITOR_CONFIG, useValue: {runInsideNgZone: true}}\n      ]\n    }).compileComponents();\n\n    fixture = TestBed.createComponent(YourWrapperComponent);\n    loader = TestbedHarnessEnvironment.loader(fixture);\n\n    // get MonacoLoader instance and wait to complete.\n    const monacoLoader = TestBed.inject(NGX_MONACO_LOADER_PROVIDER);\n    await monacoLoader.monacoLoaded();\n    fixture.detectChanges();\n  });\n\n  it(\"should get NgxMonacoEditorHarness by testid\", async () =\u003e {\n    const ngxMonaco = await loader.getHarnessOrNull(NgxMonacoEditorHarness.with({testid: \"editor-2\"}));\n    expect(ngxMonaco).toBeDefined();\n  });\n\n  it(\"should emit focus event when get focus by click\", async () =\u003e {\n    const ngxMonaco = await loader.getHarness(NgxMonacoEditorHarness);\n    await ngxMonaco.focus();\n    expect(await ngxMonaco.isFocused()).toBeTrue();\n  });\n\n  it(\"should emit blur event when lose focus\", async () =\u003e {\n    fixture.componentInstance.ngxEditor()?.focus()\n    const ngxMonaco = await loader.getHarness(NgxMonacoEditorHarness);\n    expect(await ngxMonaco.isFocused()).toBeTrue();\n\n    await ngxMonaco.blur();\n    expect(await ngxMonaco.isFocused()).toBeFalse();\n  });\n\n  it(\"should emit value when editor value changes\", async () =\u003e {\n    const theCode = \"const helloWorld = () =\u003e 'Hello world';\";\n\n    const ngxMonaco = await loader.getHarness(NgxMonacoEditorHarness);\n    await ngxMonaco.setValue(theCode);\n    expect(fixture.componentInstance.code()).toBe(theCode);\n  });\n\n  it(\"should get text from editor\", async () =\u003e {\n    const theCode = \"const helloWorld = () =\u003e 'Hello world';\";\n    fixture.componentInstance.code.set(theCode)\n    const ngxMonaco = await loader.getHarness(NgxMonacoEditorHarness);\n    expect(await ngxMonaco.getText()).toBe(theCode);\n  });\n});\n\n```\n\n\n### 2. Testing with NgxMonacoEditorFakeComponent (Recommended)\n\nDue to Monaco Editor's complexity, we recommend using `NgxMonacoEditorFakeComponent` for most testing scenarios. This fake component provides a lightweight alternative that:\n\n- Reduces test complexity\n- Improves test performance\n- Eliminates Monaco Editor initialization overhead\n- Makes tests more stable and predictable\n  \n### Advantages of Using the Fake Component\n\n 1. **Faster Tests**: No need to wait for Monaco Editor initialization\n 2. **Simpler Setup**: No need to configure Monaco loader or assets\n 3. **Better Isolation**: Tests focus on component logic rather than Monaco Editor implementation\n 4. **Predictable Behavior**: Mock responses are controlled and consistent\n 5. **Easier Debugging**: Less complexity means easier-to-debug tests\n\nChoose `NgxMonacoEditorFakeComponent` when:\n\n - You're primarily testing component logic\n - You don't need to test Monaco Editor-specific features\n - You want faster, more reliable tests\n - You're writing unit tests\n\nUse `NgxMonacoEditorHarness` when:\n\n - You need to test specific Monaco Editor features\n - You're writing integration tests\n - You need to verify Monaco Editor-specific behavior\n\nBy default, we recommend starting with the fake component for your tests and only using the real editor harness when specifically needed for integration testing.\n\n#### Setup with Fake Component\n\nIf your component imports `NgxMonacoEditorComponent` directly, you'll need to override it in your tests to use the fake component instead:\n\n```typescript\nimport { NgxMonacoEditorComponent, NgxMonacoEditorFakeComponent, NgxMonacoEditorFakeHarness } from \"@jean-merelis/ngx-monaco-editor/testing\";\n\n@Component({\n  selector: 'your-component',\n  standalone: true,\n  imports: [NgxMonacoEditorComponent], // Real component in production\n  template: `\n    \u003cngx-monaco-editor [(value)]=\"code\"\u003e\u003c/ngx-monaco-editor\u003e\n  `\n})\nclass YourComponent {\n  code = '';\n}\n```\n\nThen you need to replace the component using `overrideComponent`\n\n```typescript\ndescribe(\"YourComponent\", () =\u003e {\n  let fixture: ComponentFixture\u003cYourComponent\u003e;\n  let loader: HarnessLoader;\n\n  beforeEach(async () =\u003e {\n    await TestBed.configureTestingModule({\n      imports: [YourComponent]\n    })\n    .overrideComponent(YourComponent, {\n      remove: { imports: [NgxMonacoEditorComponent] },\n      add: { imports: [NgxMonacoEditorFakeComponent] }\n    })\n    .compileComponents();\n\n    fixture = TestBed.createComponent(YourComponent);\n    loader = TestbedHarnessEnvironment.loader(fixture);\n    fixture.detectChanges();\n  });\n\n\n  it(\"should handle value changes\", async () =\u003e {\n    const fakeEditor = await loader.getHarness(NgxMonacoEditorFakeHarness);\n    const theCode = \"const helloWorld = () =\u003e 'Hello world';\";\n    await fakeEditor.setValue(theCode);\n    expect(await fakeEditor.getText()).toBe(theCode);\n    expect(fixture.componentInstance.code).toBe(theCode);\n  });\n});\n```\n\n\n### Customizing Mock Behavior\n\nBy default, the fake component provides basic functionality for most test scenarios. However, if your component directly interacts with the Monaco Editor instance (through `editorInitialized` event), you might need to customize the mock behavior:\n\n```typescript\nimport { MOCK_MONACO_EDITOR_CONFIG } from \"@jean-merelis/ngx-monaco-editor/testing\";\n\n// Example of a component that uses Monaco Editor instance directly\n@Component({\n  template: `\n    \u003cngx-monaco-editor\n      [(ngModel)]=\"code\"\n      (editorInitialized)=\"onEditorInitialized($event)\"\n    \u003e\u003c/ngx-monaco-editor\u003e\n  `\n})\nclass EditorComponent {\n  onEditorInitialized(event: EditorInitializedEvent) {\n    // Direct interaction with Monaco Editor\n    event.editor.updateOptions({ readOnly: true });\n    event.monaco.languages.register({ id: 'myLang' });\n  }\n}\n```\n\nYou can customize the mock behavior by providing a configuration through the MOCK_MONACO_EDITOR_CONFIG token:\n\n```typescript\n/**\n * You can see a complete example of how to mock the monaco editor in\n * projects/ngx-monaco-editor/testing/src/ngx-monaco-editor-fake.component.spec.ts\n */\n\nimport { MOCK_MONACO_EDITOR_CONFIG } from \"@jean-merelis/ngx-monaco-editor/testing\";\n\n// Test setup with custom mock configuration\ndescribe(\"YourComponent\", () =\u003e {\n  beforeEach(async () =\u003e {\n    await TestBed.configureTestingModule({\n      imports: [YourComponent, NgxMonacoEditorFakeComponent],\n      providers: [{\n        provide: MOCK_MONACO_EDITOR_CONFIG,\n        useValue: {\n          initializedEvent: {\n            editor: {\n              updateOptions: jasmine.createSpy('updateOptions'),\n              // ... other methods used by your component\n            },\n            monaco: {\n              languages: {\n                register: jasmine.createSpy('register')\n              }\n            }\n          }\n        }\n      }]\n    }).compileComponents();\n  });\n\n  it('should configure editor on initialization', async () =\u003e {\n    const config = TestBed.inject(MOCK_MONACO_EDITOR_CONFIG);\n    expect(config.initializedEvent.editor.updateOptions)\n      .toHaveBeenCalledWith({ readOnly: true });\n    expect(config.initializedEvent.monaco.languages.register)\n      .toHaveBeenCalledWith({ id: 'myLang' });\n  });\n});\n\n\n```\n\nNote: If your component only uses the basic editor features (like ngModel or form control integration), you don't need to provide custom mock configuration.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjean-merelis%2Fngx-monaco-editor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjean-merelis%2Fngx-monaco-editor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjean-merelis%2Fngx-monaco-editor/lists"}