Editing document templates using TinyMCE and Angular

Kamalesh Basu
TheBrand.app
Published in
5 min readDec 12, 2019

In sizeable applications, we often need to manage document templates — contracts, emails, social media posts, and others. Document templates often tend to contain Placeholder Fragments which need to be replaced with targeted content before the document is dispatched.

You can imagine a marketplace that has to send contracts to Service providers and customers and have to insert Company name, Company ID and Contact information from their database into the contracts before sending them to relevant parties. The same thing goes for the invoicing module as well.

Another use case will be for a website to send a Drip campaign to their new sign-ups and insert the User’s name and Other targeted info into the email templates for the Drip campaign.

While editing these templates, identifiers such as <Company-Name> or #company-name are inserted in their WYSIWYG editors (or in Text Boxes). The script that parses this template is usually designed to detect these identifiers and replaces them with values from their database before dispatching the document.

Issues with this method

Common errors/annoyances that can happen when typing in these identifiers in a WYSIWYG editor:

  1. Misspelling and typos
  2. Deleting with Backspace leads to artifacts such as #company-n or <Compan. The Backspace doesn’t fully delete the fragment.

Custom TinyMCE Plugin to edit document fragment

While in the example I will cover TinyMCE, similar plugins can be built for any of the extensible editors. I will use an Angular project for the demo but you can build it for any frontend project.

Step 1. Start a new Angular project and install TinyMCE

Run the following line of codes in your terminal to create a new Angular project and install TinyMCE angular component.

$ ng n document-fragment-example$ cd document-fragment-example
$ npm install @tinymce/tinymce-angular

Step 2. (Optional) Loading TinyMCE in your project locally

If you are not loading TinyMCE from the cloud (more here), run the following line of code to install the TinyMCE code in your project:

$ npm install --save tinymce

Open your @project-root/angular.json file in your code editor and find the script section:

Assets, styles and script imports in angular.json

and import the TinyMCE javascript:

"scripts" : [
"node_modules/tinymce/tinymce.min.js"
],

and import all the necessary TinyMCE assets:

"assets" : [
{ "glob": "**/*", "input": "node_modules/tinymce/skins", "output": "/tinymce/skins/" },
{ "glob": "**/*", "input": "node_modules/tinymce/themes", "output": "/tinymce/themes/" },
{ "glob": "**/*", "input": "node_modules/tinymce/plugins", "output": "/tinymce/plugins/" }
]

Step 3. Testing TinyMCE Editor in Angular App

Open the @project-root/src/app.module.ts file and import the TinyMCE Editor module:

import { EditorModule } from '@tinymce/tinymce-angular';

and add it to the import list in the @NgModule :

@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
EditorModule
],
...

Open the @project-root/src/app.component.html and delete all contents of the file and update it as follows:

<router-outlet></router-outlet>
<editor [init]="{
base_url: '/tinymce',
suffix: '.min',
plugins: 'link',
statusbar : false
}"></editor>

If you skipped Step 2 and chose to load TinyMCE from the cloud, you should update the content of app.component.html as follows:

<router-outlet></router-outlet>
<editor apiKey="tinymce-cloud-api-key" [init]="{
plugins: 'link',
statusbar : false
}"></editor>

If you now run your angular app using $ ng serve and browse your project using http://localhost:4200 (if you set a different port use that instead of 4200), you will see the following:

TinyMCE editor in Angular Component

Step 4. Setting up the TinyMCE Plugin

Create a js directory in your @project-root/src/assets and create a file mce.contract.plugin.js . This file will register our plugin with TinyMCE. The Plugin’s purpose will be to do the following:

Preview of TinyMCE Plugin we are going to build
  1. The plugin will register a new TinyMCE plugin called contractPlugin .
  2. The plugin will add a new TinyMCE menuButton which will have 5 options to insert 5 different template fragments into the Editor content.
  3. Ensure that upon using Backspace in the TinyMCE editor, the whole template fragment is deleted.

Once we have created the Plugin file we will import it in our @project-root/angular.json file by adding to our script section:

Import newly create TinyMCE Plugin to angular.json

Step 5. Registering the Plugin and creating the menuButton

Edit the contents of mce.contract.plugin.js to register the contractPlugin with TinyMCE:

Register the Plugin with TinyMCE

and add the menuButton:

Add the Menu Button

Update your @project-root/src/app.component.html as follows (make similar changes for the cloud loaded TinyMCE version):

<editor [init]="{
base_url: '/tinymce',
suffix: '.min',
plugins: 'link contractPlugin',
toolbar1 : 'undo redo | styleselect | bold italic | link contractPlugin',
statusbar : false
}"></editor>

and you should see the following:

Custom MenuButton “Contract Templates” added to TinyMCE editor

Tip: If you are new to TinyMCE plugin creation, you will find their starter tutorials on Plugin Creation and Toolbar Buttons useful.

Step 6. Creating MenuItems and callback function

Edit the contents of mce.contract.plugin.js to add the list of MenuItems:

Add a List of Menu Items

We create a callback function which formats the editor content to be inserted and then call the function to insert the content into the editor:

Your TinyMCE editor should now update to:

Template Fragments inserted into the Editor by the Plugin

Step 7. Fix keyboard Backspace issue

If you use the backspace in your editor to delete any of the fragments, you will notice the following artifacts:

Using Backspace in the Editor doesn’t delete the template fragment but produces an unintended artifact

We can make use of the noneditable plugin from TinyMCE to fix this. Import the plugin in your @project-root/src/app.component.html (make a similar adjustment for the cloud loaded TinyMCE version):

<editor [init]="{
base_url: '/tinymce',
suffix: '.min',
plugins: 'link contractPlugin noneditable',
toolbar1 : 'undo redo | styleselect | bold italic | link contractPlugin',
statusbar : false
}"></editor>

Update the MenuItem callback action to add the mceNonEditable class to the inserted content as follows:

Our plugin is good to go!

Parting thoughts

This is a simple yet effective way to build extensions to WYSIWYG editors. Such plugins can be used to insert Tweets or Instagram posts or YouTube videos in a blog or a Stock Chart in a financial report. You can think of many such use cases.

The official TinyMCE component for Angular GitHub page provides tips on how to get the content from the WYSIWYG editor into your Component using FormsModule and ReactiveFormsModule in Angular. You can use this to save the templates on your server or in your Firebase.

Thanks for reading! You can get the complete source code from:
https://github.com/kamaleshbasu/document-fragment-example

--

--