Incorporating a Custom CKEditor5 Build into an Angular Application

I am currently in the process of developing an article editor, utilizing the Angular Integration for CKEditor5. By following the provided documentation, I have successfully implemented the ClassicEditor build with the ckeditor component.

Below are the essential files:

import { Component, OnInit } from '@angular/core';
import * as ClassicEditor from '@ckeditor/ckeditor5-build-classic';

@Component({
  selector: 'app-edit-article',
  templateUrl: './edit-article.component.html',
  styleUrls: ['./edit-article.component.scss']
})
export class EditArticleComponent implements OnInit {

  constructor() { }

  public Editor = ClassicEditor;
  articleForm: FormGroup;

  ngOnInit() {
  }

}

Template

<div class="row">
    <div class="col-12">
         <label for="">Content</label>
         <ckeditor [editor]="Editor" id="editor" class="blue-scroll--light" formControlName="content"></ckeditor>
    </div>
</div>

However, I encountered a limitation with the ClassicEditor build as it lacks several necessary plugins like text alignment, font color, and font size. In order to address this issue, I attempted to create a custom build incorporating all the desired features using the online builder provided by CKEditor. Yet, integrating this custom build into my Angular App proved challenging due to unclear documentation.

As per my understanding, I needed to include the build folder within my Angular project and import the ckeditor.js file into my component as follows:

import * as Editor from '../../../../../core/libs/ckeditor5/build/ckeditor';

Subsequently, I updated the declaration of the Editor variable to use this new import instead of the default ClassicEditor:

public Editor = Editor;

Unfortunately, upon implementing these changes, my application failed to run and presented the following error message:

ERROR Error: Uncaught (in promise): CKEditorError: ckeditor-duplicated-modules: Some CKEditor 5 modules are duplicated. Read more: https://ckeditor.com/docs/ckeditor5/latest/framework/guides/support/error-codes.html#error-ckeditor-duplicated-modules

CKEditorError: ckeditor-duplicated-modules: Some CKEditor 5 modules are duplicated. Read more: https://ckeditor.com/docs/ckeditor5/latest/framework/guides/support/error-codes.html#error-ckeditor-duplicated-modules

    at Object.<anonymous> (ckeditor.js:5)
    at Object.push../src/app/core/libs/ckeditor5/build/ckeditor.js (ckeditor.js:5)
    at i (ckeditor.js:5)
    ...

I believe this error stems from conflicting imports, despite only utilizing the ckeditor.js file included in the custom build. Strangely, this file works perfectly when referenced in a standalone HTML document.

Seeking guidance, can someone offer insights or provide a clear example on effectively integrating a Custom Build within an Angular App?

Answer №1

Upon investigation, I discovered that the issue stemmed from having another build imported in a different module of my application.

While I was solely utilizing the custom build within my EditArticle component by importing and utilizing that file, there were other components in separate modules importing and using the ClassicEditor build installed through NPM, which appeared to be causing the error.

The solution did not involve outright removing the ClassicEditor package or the import ClassicEditor statement. Instead, it required ensuring that the specific import was not utilized elsewhere in the app as Angular likely removes all unused imports during compilation.

After rectifying this, the application functioned smoothly with my custom build.

To clarify, both these imports can coexist in the same file or across multiple components:

import * as ClassicEditor from '@ckeditor/ckeditor5-build-classic';
import * as Editor from 'src/app/core/libs/ckeditor5/build/ckeditor';

However, only one should be actively used throughout the entire app. For instance, if an Editor exists in both `Component1` and `Component2`, both builds can be imported but only one should be designated for use in the Editor property declaration across all components:

This setup is effective:

Component1

import * as ClassicEditor from '@ckeditor/ckeditor5-build-classic';
import * as Editor from 'src/app/core/libs/ckeditor5/build/ckeditor';

public Editor = Editor;

Component2

import * as ClassicEditor from '@ckeditor/ckeditor5-build-classic';
import * as Editor from 'src/app/core/libs/ckeditor5/build/ckeditor';

public Editor = Editor;

This configuration will NOT work:

Component1

import * as ClassicEditor from '@ckeditor/ckeditor5-build-classic';
import * as Editor from 'src/app/core/libs/ckeditor5/build/ckeditor';

public Editor = Editor;

Component2

import * as ClassicEditor from '@ckeditor/ckeditor5-build-classic';
import * as Editor from 'src/app/core/libs/ckeditor5/build/ckeditor';

public Editor = ClassicEditor;

If preferred, eliminating the unused build from the imports entirely is also a valid approach. Just remember to maintain consistency by using the same build throughout the application.

Answer №2

     console.log(this.customEditor.pluginsList.map( plugin => plugin.pluginName ));
  }

Gather the list of plugins from the custom editor build. 
The custom editor includes :
["Alignment", "AutoImage", "Autoformat", "Autosave", "BlockQuote", "Bold", "CodeBlock", "Essentials", "ExportPdf", "ExportWord", "FontBackgroundColor", "FontColor", "FontFamily", "FontSize", "Heading", "Highlight", "HorizontalLine", "Image", "ImageCaption", "ImageInsert", "ImageResize", "ImageStyle", "ImageToolbar", "ImageUpload", "Indent", "IndentBlock", "Italic", "Link", "List", "Markdown", "MathType", "MediaEmbed", "MediaEmbedToolbar", "PageBreak", "Paragraph", "PasteFromOffice", "SpecialCharacters", undefined, undefined, undefined, undefined, undefined, "Strikethrough", "Subscript", "Superscript", "Table", "TextTransformation", "WordCount"]


take the displayed list within [] and replace xxxx with it.

<ckeditor [config]="{toolbar:[xxxx] }"

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The mysterious anomaly in Vue.js

I am attempting to assign a data object named types upon receiving a response in the ready() method. This is what I have: export default { data () { return { types: null } }, ready () { TypeService.showAll(1) .then(functio ...

Generate a CSV file using Javascript

I am working with an HTML table (table id='testTable') and a button in the HTML code: <button id="btnExport" onclick="javascript:xport.toCSV('testTable');">CSV</button> There is also JavaScript code involved: toCSV: func ...

Incorporate the block-input feature from sanity.io into your next.js blog for enhanced functionality

Currently, I'm in the process of creating a blog using next.js with sanity.io platform. However, I am facing some difficulties when it comes to utilizing the code-input plugin. What's working: I have successfully implemented the code component b ...

Having trouble implementing pagination for news-api in Vue.js2?

I am currently working on implementing a basic pagination feature in my Vue component specifically for the newsapi.org API. While my initial API call in the created hook is functioning as expected, I am encountering difficulties navigating to different pa ...

Guide on handling asynchronous data return within a reducer

I'm struggling to properly handle the state when receiving data from the back-end of my application. This is the code I have: if (action.type === actionTypes.getList) { const id = action.payload.userId; Axios.post(`${apiUrl}/lists`, { ...

Ways to deactivate selecting rows in a datatable

Is there a way to deactivate the select feature specifically within datatables? An example of using ctrl+a for disabling select all function is available here https://i.stack.imgur.com/RQNXT.png ...

What is the correct way to declare a class as global in TypeScript?

To prevent duplication of the class interface in the global scope, I aim to find a solution that avoids redundancy. The following code snippet is not functioning as intended: lib.ts export {} declare global { var A: TA } type TA = typeof A class A { ...

Obtaining HTML elements from JSON using jQuery (i.e., the opposite of serializing with Ajax)

I am looking to extract values from a set of controls (INPUT, SELECT, TEXTAREA) within a DIV and send them as JSON via Ajax to a server. Utilizing jQuery's serializeArray makes this process easy. After sending the JSON data, I expect the server to re ...

Creating a javascript function to update content on click

Recently, I've been designing a webpage and encountered an issue. I want the text in a specific area to change whenever a user clicks on a link. Below is the code snippet related to the section I want to modify using a JavaScript function. <div id ...

What causes duplicate packages to appear in Bower at times?

There appears to be two identical packages available for the Sugar javascript library, sugar and sugarjs. Are these packages interchangeable or are they being maintained separately by different individuals? ➔ bower info sugarjs bower sugarjs#* ...

Capturing screenshots with Selenium in Node.js is proving to be quite sluggish

My current project involves using Selenium with Mocha in Node.js for UI testing on a website. I want to capture screenshots after each test to review and share the results visually. The challenge arises when there are AJAX calls and JavaScript animations ...

What is the process of generating enum values using ES6 in Node.js?

Can JavaScript support enumerations with assigned integer values, similar to how other programming languages handle it? In C#, for instance, I can define an enum as follows: enum WeekDays { Monday = 0, Tuesday =1, Wednesday = 2, Thursday ...

How can I create a Material ui Card with a border-less design?

After reviewing the information provided, I noticed that you can set the option to have it as variant="outlined" or raised However, I am curious if there is a method to create the card without any visible borders at all? ...

How can JavaScript allow access to files outside of a web server environment? Could .htaccess provide a

Currently, I'm facing a challenge with my local server on Mac 10.8. I am trying to serve files such as videos and images from an external hard drive. The path for the external hard drive is HD: /Volumes/ while the web server's path is /Library/Se ...

react-leaflet LayerSelection creates redundant entries in table

Here is the React version I am using: 16.0.0 And for react-leaflet: 1.6.6 I recently attempted to implement a layer controller on my map which consists of two layers, each containing multiple markers. Below is an example of what I have been working on. i ...

Using JSTL tags may result in returning null or empty values when making Javascript calls or populating HTML

This strange error is puzzling because it appears on some of the webpages I create, but not on others, even though the elements are exactly the same. For instance, this issue does not occur: <main:uiInputBox onDarkBG="${hasDarkBG}" name="quest ...

Scrolling with Jquery window.scrollTo results in the page becoming unresponsive

I'm currently revamping a website that features a header with 100% screen height, but I need it to shrink down to 0px when a user starts scrolling. The issue I'm facing is that once the header shrinks to 0px, the page content ends up slightly abo ...

What is the best way to transform a list of Python+Flask objects into a list of JavaScript objects?

Here's a Flask application that showcases a list of objects. from flask import * app = Flask(__name__) class Entry: def __init__(self, name, surname): self.name = name self.surname = surname entries = [] entries.append(Entr ...

What is the best way to import and export modules in Node.js when the module names and directories are given as strings?

Here is the structure of my folder: modules module-and index.js module-not index.js module-or index.js module-xor index.js moduleBundler.js The file I'm currently working on, moduleBundler.js, is re ...

In JavaScript, generate a new column when the text exceeds the height of a div

Is it possible to create a multicolumn layout in HTML that flows from left to right, rather than top to bottom? I am looking to define the height and width of each text column div, so that when the text overflows the box, a new column is automatically ge ...