How to setup Ace editor in Angular?

How to setup Ace editor in Angular?

Β·

6 min read

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

⏬ 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 definitions files

πŸ“„ 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
  4. i. 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.

    ii. We are setting default font-size of editor to 14px. There are lots of configuration options which Ace editor provides, please check them here

    iii. Then, we are attaching Ace editor to our #editor element.

    iv. 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:

ace editor in angular output

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:

ace editor in angular output

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

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:

ace editor 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:

supported events

Let's see the output:

ace editor in action

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

ReadMe Card

πŸ™ 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

Photo by ExnD on Unsplash

If you liked this article, chances are you'll like my other articles, too:

See you at next article… πŸ‘‹πŸ‘‹πŸ‘‹

Did you find this article valuable?

Support Dharmen Shah by becoming a sponsor. Any amount is appreciated!