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

Unable to retrieve value 'includes' from null object

Currently, I am utilizing Vue.js along with JavaScript. In my code, there is an array of objects named products, each containing a special property called smallest_unit_barcode. My goal is to filter out only those products that have a barcode similar to a ...

Ways to extract the value from a jQuery object

How can I retrieve the selected time value using a jQuery plugin and save it on a specific input element within the page? Refer to the plugin and code provided below: http://jsfiddle.net/weareoutman/YkvK9/ var input = $('#input-a'); input.cloc ...

What is the best way to connect to a library using a script within a Typescript React application?

I'm a newbie to React and haven't worked on web development in years, so I'm facing a basic issue: Currently, I'm working on implementing a Stripe-based payment flow in a React web app (written in Typescript) and I've hit a roadbl ...

Unable to wrap the strings from the database in a span element

I have a challenge where I need to enclose the first and last strings that represent the title and price of a product within a div using a span tag. These strings are dynamic, sourced from a database, and differ for each product. I have attempted to use th ...

Converting a JavaScript variable into PHP using ajax: A comprehensive guide

Can someone please help me troubleshoot this code for passing a JavaScript variable to PHP? It doesn't seem to be working properly. I want to extract the value of an ID from JavaScript and send it over to PHP. <!DOCTYPE html> <html> ...

Utilizing React SSR to dynamically import components based on API response

I am currently working on a SSR React app using the razzle tool, with the server running on the express framework. My goal is to dynamically load React components based on the value included in an API response. My folder structure looks like this: views ...

Trouble with apostrophes rendering in JavaScript on WordPress posts

My current challenge involves adding a post to Wordpress using an external script. This post includes a JavaScript section that contains an iframe for displaying movies. Knowing that Wordpress splits default tags, I have implemented a special plugin to han ...

Is data binding not functioning properly in Angular 8?

This query has been raised multiple times in the past and I have reviewed all the suggested solutions. However, I am encountering a common issue - how to retrieve data from the parent component to the child component. I'm unsure of where I'm goin ...

How can I use a button to save all changes made in a JqGrid checkbox column simultaneously?

In my jqgrid, there is a column named 'asistencia' which displays data from a database as checkboxes. These checkboxes are pre-checked based on the property formatoptions: {disabled : false}. I would like to implement a 'save' button th ...

Handling session expiration in ASP.NET MVC when making an AJAX call by redirecting to the login page

I'm currently learning ASP.NET MVC and I'm a newbie in it, so I'm struggling to find a solution for a specific problem. If anyone has encountered this issue before, I would appreciate any advice. Thank you! In my project, I am using ASP.NET ...

Unable to retrieve values from nested objects in component.html

Hey fellow tech enthusiasts, I'm currently dealing with a complex nested JSON object retrieved from an API. Here's a snippet of the object: profile : { title:"Mr", personalInfo:{ fullNames: "John Doe", id ...

Mongoose Exception: Question does not have a constructor

After coming across numerous questions on stack overflow related to this error without finding a solution that works for me, I've decided to ask my own question. (probably due to my limited understanding of javascript/node/mongoose) The modules I am ...

Protractor: Moving further down the page

One issue I encountered is with a button on my page that becomes visible only when the user scrolls down. As a result, Protractor tests are throwing an error: UnknownError: unknown error: Element is not clickable at point (94, 188). I attempted to reso ...

What is the optimal location for storing component fetch logic?

When should I make a REST request to retrieve data for a Vue component called Page, specifically for the properties title and content? Also, where is the best place to handle this logic? Currently, I am trying to fetch the data on the component's rea ...

What is the method for determining the new point coordinates and direction vector after a rotation of degrees in three.js?

How can I determine the coordinates of point A to H after rotating a certain number of degrees and aligning them with direction vector (-42, 51, 11) using three.js? Thank you in advance for your help and please forgive any mistakes in my English. Best reg ...

Transmit data via AJAX to the RequestBody

Although seemingly simple, this issue has proven to be quite challenging. I am confident that it can be easily resolved, but the solution continues to elude me. Thank you for any assistance you can provide. Here is the code snippet in question : var samp ...

What is the best way to create a sign-up box that appears on the same page when you click on the sign-up button

I am interested in implementing a 'sign up' box overlay at the center of my index page for new users who do not have an account. I would like them to be able to easily sign up by clicking on the 'sign up' button. Once they complete the ...

Guide on including a partial view in a modal using Jquery

Looking to enhance the parameters of a list of products by displaying a modal window for editing? You can achieve this by including a button in each row that triggers the modal window... https://i.sstatic.net/kDw6q.png The Edit button code in Index.csht ...

Standardized identification code

My request response needs to be defined, but the key name may vary. It will always be a string, but the specific key depends on the request. These are the possible responses: { someRequest: { message: 'success', status: 200 } } { someOtherReques ...

Issues with displaying HTML5 audio player in iOS Chrome and Safari browsers

My html5/jquery/php audio player is working well on desktop browsers, but when I tried testing it on iOS, all I could see was a grey track bar. I suspect that the controls are hidden behind the track bar because sometimes the associated file starts playing ...