Search code examples
angularnpmace-editor

Angular 2 include ng2-ace package



I've been trying to get the npm package ng2-ace working, for using the ace-editor tag on a div, but I always the the error 'Cannot find module ng2-ace'.


So this is my app.component.ts

import { Component } from '@angular/core';

import { AceEditorDirective } from 'ng2-ace';

@Component({
  selector: 'my-app',
  directives: [AceEditorDirective],
  templateUrl: 'app/app.component.html'
})

export class AppComponent { }


And this is my app.component.ts

/**
 * System configuration for Angular samples
 * Adjust as necessary for your application needs.
 */
(function (global) {
  System.config({
    paths: {
      // paths serve as alias
      'npm:': 'node_modules/',
    },
    // map tells the System loader where to look for things
    map: {
      // our app is within the app folder
      app: 'app',
      // angular bundles
      '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
      '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
      '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
      '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
      '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
      '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
      '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
      '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
      // other libraries
      'rxjs':                      'npm:rxjs',
      'angular-in-memory-web-api': 'npm:angular-in-memory-web-api',

      'brace': 'npm:brace',
      'w3c-blob': 'npm:w3c-blob',
      'buffer': 'npm:buffer-shims',
      'ng2-ace': 'npm:ng2-ace'
    },
    // packages tells the System loader how to load when no filename and/or no extension
    packages: {
      app: {
        main: './main.js',
        defaultExtension: 'js'
      },
      rxjs: {
        defaultExtension: 'js'
      },
      'angular-in-memory-web-api': {
        main: './index.js',
        defaultExtension: 'js'
      },

      'ng2-ace': {
        format: 'cjs',
        defaultExtension: 'js',
        main: './index.js'
      },

      'w3c-blob': {
        format: 'cjs',
        defaultExtension: 'js',
        main: './index.js'
      },

      'brace': {
        format: 'cjs',
        defaultExtension: 'js',
        main: './index.js'
      },

      'buffer': {
        format: 'cjs',
        defaultExtension: 'js',
        main: './index.js'
      },
    }
  });
})(this);

brace is a dependency of ng2-ace which has a dependency w3c-blob which also has the depencey buffer.
I just started working with Angular 2 so I'm not very accustomed to the workflow.

Anyway Thanks in advance!


Solution

  • You can try the following steps to configure ace-editor.

    step 1

    Install packages

    npm i brace w3c-blob buffer base64-js ieee754 --save
    

    step 2

    Create directive:

    import { Directive, ElementRef, EventEmitter, Input, Output } from '@angular/core';
    
    import 'brace';
    import 'brace/theme/monokai';
    import 'brace/mode/javascript';
    declare var ace: any;
    
    @Directive({
      selector: '[ace-editor]'
    })
    export class AceEditorDirective {
      _readOnly: any;
      _theme: any;
      _mode: any;
    
      editor: any;
      oldVal: any;
    
      @Input() set options(value) {
        this.editor.setOptions(value || {});
      }
    
      @Input() set readOnly(value) {
        this._readOnly = value;
        this.editor.setReadOnly(value);
      }
    
      @Input() set theme(value) {
        this._theme = value;
        this.editor.setTheme(`ace/theme/${value}`);
      }
    
      @Input() set mode(value) {
        this._mode = value;
        this.editor.getSession().setMode(`ace/mode/${value}`);
      }
    
      @Input() set text(value) {
        if(value === this.oldVal) return;
        this.editor.setValue(value);
        this.editor.clearSelection();
        this.editor.focus();
      }
    
      @Output() textChanged = new EventEmitter();
      @Output() editorRef = new EventEmitter();
    
      constructor(private elementRef: ElementRef) {
        const el = elementRef.nativeElement;
        el.classList.add('editor');
    
        this.editor = ace.edit(el);
    
        setTimeout(() => {
          this.editorRef.next(this.editor);
        });
    
        this.editor.on('change', () => {
          const newVal = this.editor.getValue();
          if(newVal === this.oldVal) return;
          if(typeof this.oldVal !== 'undefined') {
            this.textChanged.next(newVal);
          }
          this.oldVal = newVal;
        });
      }
    }
    

    step 3

    Configure systemjs.config.js

      map: {
        ...
    
        'brace': 'npm:[email protected]',
        'w3c-blob': 'npm:w3c-blob/index.js',
        'buffer': 'npm:buffer/index.js',
        'base64-js': 'npm:base64-js/index.js',
        'ieee754': 'npm:ieee754/index.js'   
      },
      packages: {
        ...
        brace: {
          main: './index.js',
          defaultExtension: 'js'
        }
      }
    

    step 4

    Include the AceEditorDirective in declarations list of your module

    @NgModule({
      imports:      [ BrowserModule ],
      declarations: [ AppComponent, AceEditorDirective ],
      bootstrap:    [ AppComponent ]
    })
    export class AppModule { }
    

    Enjoy