I just created an angular2 project with the latest angular-cli tool. I now want to get the ace editor up and running using the ng2-ace library. I want to do it in a clean approach using SystemJS as the module loader.
I did
npm install --save ng2-ace
then I added the following two lines to angular-cli-builds.js
to the vendorNpmFiles
array
'ng2-ace/index.js',
'brace/**/*.js
then I added the following to system-config.ts
const map: any = {
'ng2-ace': 'vendor/ng2-ace',
'brace': 'vendor/brace'
};
/** User packages configuration. */
const packages: any = {
'brace': {
format: 'cjs',
defaultExtension: 'js',
main: 'index.js'
},
'ng2-ace': {
format: 'cjs',
defaultExtension: 'js',
main: 'index.js'
}
};
Now I tried importing the directive from a component
import { AceEditorDirective } from 'ng2-ace';
This makes the compiler ng serve
aborting with the following error:
The Broccoli Plugin: [BroccoliTypeScriptCompiler] failed with:
Error: Typescript found the following errors:
Cannot find module 'ng2-ace'.
I tried to follow the Readme from angular-cli and got the google material design library working. However, I don't know what I do wrong when trying to load the ng2-ace library.
I think the reason this is so hard is that there's no typings library provided. I was able to get the rough equivalent of this working by adding a few things. My version has a pretty static configuration but you can enhance it.
system-config needs this:
const map:any = {
'brace': 'vendor/brace',
'w3c-blob': 'vendor/w3c-blob',
'buffer': 'vendor/buffer-shims'
};
it may also need:
const packages:any = {
'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'
}
};
Then you also need to add these things as npm dependencies in angular-cli-build.js:
module.exports = function(defaults) {
return new Angular2App(defaults, {
vendorNpmFiles: [
/* your stuff goes here, then add: */
'brace/**/*.js',
'w3c-blob/index.js',
'buffer-shims/index.js'
]
});
That pretty much gets you everything you need as far as dependencies are concerned. At this point I added my own directive. The important parts are here:
import { Directive, ElementRef, EventEmitter } from '@angular/core';
Now import brace itself plus whatever modes and themes you will be using:
import 'brace';
declare let ace;
import 'vendor/brace/mode/javascript';
import 'vendor/brace/theme/monokai';
The 'declare let ace' lets you have access to brace even though there's no typings and it's not a real typescript module.
I named my directive 'js-editor' and you attach it to a tag of an appropriate height and width. The docs for brace say to apply a 'block' style to the div it as well. Then declare the directive:
@Directive({
selector: '[js-editor]',
inputs: ['text'],
outputs: ['textChanged', 'editorRef']
})
export class JsEditor {
editor : any;
textChanged : EventEmitter<any>;
editorRef : EventEmitter<any>;
value : string;
set text(value) {
// if(value === this.oldVal) return;
// this.editor.setValue(value);
// this.editor.clearSelection();
this.editor.focus();
}
constructor(elementRef : ElementRef) {
this.textChanged = new EventEmitter();
this.editorRef = new EventEmitter();
const el = elementRef.nativeElement;
el.classList.add('editor');
Setting the base path is the key element to brace being able to find modes and themes. This is really the wrong place to set it - it should be done globally, and ONLY ONCE ... but this was just an experiment to see if it would work so I did it here:
ace.config.set('basePath', 'vendor/brace');
Finally, create the editor:
this.editor = ace.edit(el);
and then set your mode and theme. Note that these modes/themes LOOK like paths, but they really are not. Ace (or perhaps Brace) will use these strings to generate the path using the basePath above:
this.editor.getSession().setMode('ace/mode/javascript');
this.editor.setTheme('ace/theme/monokai');
setTimeout(() => {
this.editorRef.next(this.editor);
});
this.editor.on('change', () => {
/* do whatever you want here */
});
}
}
That's the general idea. It really needs to be wrapped up into a nice configurable directive along the lines of ng2-ace but I'm not the right guy to do that, I just wanted to get you headed in the right direction.
--Chris
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With