How to setup Ace editor in Angular?

Dharmen Shah
6 min readOct 28, 2020

In this article, I will show you how to ⚡ quickly setup ✏️ Ace editor in 🅰️ Angular without any other 3rd party libraries.

✏️ Ace Editor

Ace is an embeddable code editor written in JavaScript. It matches the features and performance of native editors such as Sublime, Vim and TextMate. It can be easily embedded in any web page and JavaScript application. Ace is maintained as the primary editor for Cloud9 IDE and is the successor of the Mozilla Skywriter (Bespin) project.

Both Cloud9 IDE and Mozilla are actively developing and maintaining Ace.

👨‍💻 Let’s talk Coding

📁 Create a workspace

Open up your terminal and:

npm i -g @angular/cli
ng new ace-angular --defaults --minimal

👉 Do not use --minimal option in production applications, it creates a workspace without any testing frameworks. You can read more about CLI options.

At this point, your folder structure should look like this and it is going to be same till the end:

Folder structure
Folder structure

⏬ Install Ace editor

We will install pre-packaged version of Ace from npm:

npm i ace-builds

🛠️ Setup editor

One advantage of using ace-builds package directly in Angular is that they already provide support for Typescript. You can check in their repo, they have their type definitions files at place:

Type definition files of Ace builds repo
Type definition files of Ace builds repo

📄 app.component.ts

Clear all the content of the file and start with below:

import { AfterViewInit, Component, ElementRef, ViewChild } from "@angular/core";

// 1️⃣
import * as ace from "ace-builds";

// 2️⃣
@Component({
selector: "app-root",
template: `
<div
class="app-ace-editor"
#editor
style="width: 500px;height: 250px;"
></div>
`,
styles: [
`
.app-ace-editor {
border: 2px solid #f8f9fa;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
}
`,
],
})
export class AppComponent implements AfterViewInit {

// 3️⃣
@ViewChild("editor") private editor: ElementRef<HTMLElement>;

// 4️⃣
ngAfterViewInit(): void {
ace.config.set("fontSize", "14px");
const aceEditor = ace.edit(this.editor.nativeElement);
aceEditor.session.setValue("<h1>Ace Editor works great in Angular!</h1>");
}
}

Let’s see what’s happening here:

  1. First, we are importing ace from ace-builds package.
  2. Then, we are setting HTML template. Note that height and width are required, otherwise editor won't load. I have also added styling, you can skip that if you want.
  3. After above, we are querying our editor using @ViewChild

Last step can be divided in multiple-stpes:

  1. To access queried child of @ViewChild, we need to use ngAfterViewInit life-cycle hook. Becuase view queries are set before the ngAfterViewInit callback is called.
  2. We are setting default font-size of editor to 14px. There are lots of configuration options which Ace editor provides, please check them here.
  3. Then, we are attaching Ace editor to our #editor element.
  4. And last, we are setting up the default value. You can check the the how-tos of Ace editor at its how-to guide.

Let’s look at the output:

Browser output after initial setup
Browser output after initial setup

Congratulations 🎉🎉🎉. You have completed the setup of Ace editor. 👏👏👏.

🔭 Further usage

In real-world scenarios, you would also want to enable syntax highlighting and get the value from editor. Let’s see it in action.

🌄 Set theme and syntax highlighting

In app.component.ts make below changes:

...
ngAfterViewInit(): void {
ace.config.set("fontSize", "14px");
const aceEditor = ace.edit(this.editor.nativeElement);
aceEditor.session.setValue("<h1>Ace Editor works great in Angular!</h1>");

// 🚨 Added
aceEditor.setTheme('ace/theme/twilight');
aceEditor.session.setMode('ace/mode/html');
}

Cool. Let’s see the output in the browser:

Browser output after initial setup
Browser output after setting theme and mode

As you can see, highlighting and syntax aren’t enabled. Let’s see if there is any error in browser console:

Browser console error
Browser console error

Error says: Unable to infer path to ace from script src, use ace.config.set(‘basePath’, ‘path’) to enable dynamic loading of modes and themes or with webpack use ace/webpack-resolver.

Which means Ace is not able to find relevant files for themes and syntax highlighting.

You see, they have already given a solution, too in the error console. That is to use: ace.config.set('basePath', 'path'). By default ace detects the url for dynamic loading by finding the script node for ace.js. This doesn't work if ace.js is not loaded with a separate script tag, and in this case it is required to set url explicitely. And the url should be pointing to a folder that contains ace nodes.

Thanks to unpkg.com, we can get the needed URL:

https://unpkg.com/ace-builds@1.4.12/src-noconflict

Let’s update it in our code:

...
ngAfterViewInit(): void {
ace.config.set("fontSize", "14px");

// 🚨 Added
ace.config.set('basePath', 'https://unpkg.com/ace-builds@1.4.12/src-noconflict');

const aceEditor = ace.edit(this.editor.nativeElement);
aceEditor.session.setValue("<h1>Ace Editor works great in Angular!</h1>");

aceEditor.setTheme('ace/theme/twilight');
aceEditor.session.setMode('ace/mode/html');
}

Check the output:

Browser output after setting basePath
Browser output after setting basePath

✍️ Get value from editor

...
ngAfterViewInit(): void {
ace.config.set("fontSize", "14px");
ace.config.set(
"basePath",
"https://unpkg.com/ace-builds@1.4.12/src-noconflict"
);
const aceEditor = ace.edit(this.editor.nativeElement);
aceEditor.session.setValue("<h1>Ace Editor works great in Angular!</h1>");
aceEditor.setTheme("ace/theme/twilight");
aceEditor.session.setMode("ace/mode/html");

// 🚨 Added
aceEditor.on("change", () => {
console.log(aceEditor.getValue());
});
}

I think it’s clear from the code how to get value 😉. You should check all the events supported by Ace editor. Thanks to Typescript and VS Code, you can see it while editing:

VS Code intellisense
VS Code intellisense

Let’s see the output:

Browser output when getting value

Cool, with that we are done 👍

The final version of app.component.ts looks like below:

import { AfterViewInit, Component, ElementRef, ViewChild } from "@angular/core";
import * as ace from "ace-builds";

@Component({
selector: "app-root",
template: `
<div
class="app-ace-editor"
#editor
style="width: 500px;height: 250px;"
></div>
`,
styles: [
`
.app-ace-editor {
border: 2px solid #f8f9fa;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
}
`,
],
})
export class AppComponent implements AfterViewInit {
@ViewChild("editor") private editor: ElementRef<HTMLElement>;

ngAfterViewInit(): void {
ace.config.set("fontSize", "14px");
ace.config.set(
"basePath",
"https://unpkg.com/ace-builds@1.4.12/src-noconflict"
);
const aceEditor = ace.edit(this.editor.nativeElement);
aceEditor.session.setValue("<h1>Ace Editor works great in Angular!</h1>");
aceEditor.setTheme("ace/theme/twilight");
aceEditor.session.setMode("ace/mode/html");
aceEditor.on("change", () => {
console.log(aceEditor.getValue());
});
}
}

✔️Conclusion

We saw how we can simply use Ace editor in Angular without any 3rd party library usage.

Code is available at Github repo: shhdharmen/ace-angular

Code repo
Code repo

🙏 Thank You

for reading my article. Let me know your thoughts in the comments section.

I am also available on twitter as @shhdharmen if you want to say hi 👋.

And yes, always believe in yourself… 😀

Photo by ExnD on Unsplash

--

--