Guide to Using TinyMCE Angular to Create a Rich Text Editor

Introduction

TinyMCE is a feature-rich, What You See Is What You Get (WYSIWYG) editor written in JavaScript. It's often built into web applications to let users easily format content without needing to know HTML.

TinyMCE gives you an intuitive interface, much like desktop word processors (such as Microsoft Word). This allows users to:

  • Format text (bold, italic, underline).
  • Create lists.
  • Insert images/videos.
  • Make tables.
  • Directly view/edit the HTML source code.

It essentially acts as a bridge between the end-user and complex HTML code.

Key Advantages

  • Easy to Use (Familiar Interface): The friendly and familiar interface helps users quickly get comfortable and create high-quality content.
  • Highly Extensible (Extensibility): It supports hundreds of plugins and customizations, allowing developers to add specialized functions (like spell check, advanced file management, etc.).
  • Cross-Platform Compatibility: It works reliably across all modern browsers and integrates easily with any frontend framework or library (React, Angular, Vue, etc.).
  • Clean HTML Output: TinyMCE is designed to produce valid and optimized HTML code, ensuring content displays correctly on different devices.

How to Use It

In this article, I'll guide you through using TinyMCE in an Angular project. You can apply this setup to React and Vue.js projects with similar configurations because TinyMCE supports them too.

1. Installation

First, you need to install the following packages:

yarn add @tinymce/tinymce-angular tinymce


2. Component Setup (HTML)

Next, create the component with the following content:

<editor [apiKey]="apiKey" [init]="init" [initialValue]="initialValue" #editorEl />
<button (click)="getContent()">Get content</button>


3. Typescript File

Here is the accompanying TypeScript file:

import { CommonModule } from '@angular/common';
import { Component, ElementRef, ViewChild } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { EditorComponent, EditorModule } from '@tinymce/tinymce-angular';

@Component({
  selector: 'tinymce-app',
  imports: [FormsModule, CommonModule, EditorModule],
  templateUrl: './index.html',
})
export class TinyMCEComponent {
  @ViewChild('editorEl') editorEl!: EditorComponent;
  @ViewChild('editorContainer') editorContainer!: ElementRef;

  readonly apiKey = '<api key>';
  readonly licenseKey = 'gpl';
  readonly initialValue = `<p>line 1</p>
  <p style="background-color: #236fa1">line 2</p>
  <div><img src="https://cdn-icons-png.flaticon.com/512/10278/10278187.png" width="200px" height="200px"></div>`;

  readonly init: EditorComponent['init'] = {
    plugins: [
      'lists',
      'link',
      'image',
      'table',
      'code',
      'help',
      'wordcount',
      'anchor',
      'autolink',
      'charmap',
      'codesample',
      'emoticons',
      'link',
      'lists',
      'media',
      'searchreplace',
      'table',
      'visualblocks',
      'wordcount',
      'quickbars',
      'preview',
      'editimage',
      'hr',
      'fontpreview',
      'indentation',
      'paste',
      'fullscreen',
      'imagetools',
    ],
    toolbar:
      'undo redo | bold italic underline strikethrough | hr | fontfamily fontsize blocks | alignleft aligncenter alignright alignjustify | table tableprops tablerowprops tablecellprops | outdent indent | numlist bullist | forecolor backcolor removeformat | charmap | fullscreen preview | image link',
    resize: false,
    statusbar: false,
    images_upload_handler: (_blobInfo, _progress) =>
      Promise.resolve('https://cdn-icons-png.flaticon.com/512/10278/10278187.png'),
    setup: (editor) => {
      editor.on('drop', (e) => {
        e.preventDefault();
        editor.execCommand(
          'mceInsertContent',
          false,
          `<img src="https://cdn-icons-png.flaticon.com/512/10278/10278187.png" alt="Uploaded Image" />`
        );
      });
    },
  };

  getContent(): void {
    console.log(this.editorEl.editor.getContent());
  }
}

Explanation

  • `apiKey`: Used to authenticate with TinyMCE Cloud and activate a subscription. TinyMCE Cloud offers a free tier with a monthly limit. You can get an API key after creating an account here.
  • `licenseKey`: Used for self-hosted premium plugins to remove error messages. This is only necessary for paid/premium plugins in a self-hosted environment.
  • `initialValue`: This is the initial content that the text editor loads when it first starts up.
  • `plugins`: These are the features added to the text editor. You can add or remove plugins based on your needs. You can see supported plugins here.
  • `toolbar`: These are the function icons displayed on the text editor. You can customize this as needed. See the configuration options here.
  • `images_upload_handler`: This is one of the functions the editor supports. When an image is uploaded, this code block executes and returns a Promise string of the image URL to be inserted into the editor. In a real-world application, you would customize this function to handle the actual image upload and get the saved image URL to insert.
  • `setup`: Used to configure events. Here, I configure the `drop` event to execute when a file is dropped into the editor. The `editor.execCommand` function is used to insert an `<img>` tag as a placeholder for when an image is dragged into the editor, inserting the image at the cursor's position.

The result is that the text editor's resources will be fetched directly from TinyMCE Cloud


When the content in the text editor changes and you click Get content, you will receive the following HTML content:



Self-Hosting TinyMCE

The guide above uses TinyMCE Cloud. This is only free when you use it in a localhost environment. When you deploy it, you'll need to add your domain to a whitelist, and you'll be limited in usage each month (if you use the free plan). To use the open-source, community-supported version, you need to make the following changes:

1. Update `angular.json`

Add the TinyMCE resources to the `assets` field in your `angular.json` file:

{
  "projects": {
    "core-testing": {
      "architect": {
        "build": {
          "builder": "@angular/build:application",
          "options": {
            "assets": [
              {
                "glob": "**/*",
                "input": "./node_modules/tinymce",
                "output": "/tinymce"
              }
            ],
            ...


2. Update `init` Configuration

Next, update the `init` value with the `base_url` pointing to the TinyMCE asset path:

readonly init: EditorComponent['init'] = {
    base_url: '/tinymce',
    ...


3. Update Editor Component (HTML)

Finally, add the `licenseKey` field when using the editor component. This is to declare that you're using the free, open-source version of TinyMCE under the terms of the GPL (General Public License):

<editor [licenseKey]="licenseKey" [init]="init" [initialValue]="initialValue"  #editorEl />


The result of this is that the TinyMCE packages are loaded directly from your own host, so you won't have request limits after deployment.


See more articles here.

Comments

Popular posts from this blog

All practice series

Deploying a NodeJS Server on Google Kubernetes Engine

Setting up Kubernetes Dashboard with Kind

Using Kafka with Docker and NodeJS

Monitoring with cAdvisor, Prometheus and Grafana on Docker

Kubernetes Practice Series

Kubernetes Deployment for Zero Downtime

Practicing with Google Cloud Platform - Google Kubernetes Engine to deploy nginx

NodeJS Practice Series

Helm for beginer - Deploy nginx to Google Kubernetes Engine