A Detailed Approach to Setting Up CKEditor with Angular

Opeoluwa Iyi-Kuyoro
The Startup
8 min readMay 27, 2019

--

You may be working on a blog for yourself, and wondering how you are going to manage the rich text content. In this article, I try to show a step by step approach of setting up a rich text editor that supports image uploads to a cloud service.

Who is this article for?

  • I work with Angular or I have some knowledge about how Angular works.
  • I am trying to build an editor that uploads the images to a cloud service in this case Cloudinary.
  • I already know how to work with CKEditor but I can’t seem to figure out the image upload aspect of it.
  • I am looking for a tool that helps hook up automatic image uploads from CKEditor to Cloudinary.

What Will we be Building?

We are going to be building a very simple web app that allows the user to create rich text content on the web. After writing and submitting the content, the user will be redirected to a different page where the content is displayed for reading. The sample code for the project can be found t.

Here is what the editor page would look like.

A screenshot of the editor page

Setting up the angular project

The quickest way to get an Angular app setup is to use the CLI. In this tutorial, we will be using Angular 7 which is the latest version at the time of making this tutorial. So go ahead and install that globally if you haven't already.

npm i --save -g @angular/cli

The next thing you will want to do would be to set up the Angular project. I am going to call my project RichEditor. You can do that by creating the angular project using the command below. Please setup with Angular routing and CSS when prompted.

ng new RichEditor

This project was built with Angular 7. Based on feedback, you will experience an error with the image upload adapter if you use version ^8.2.~. To fix this, change the es target in your tsconfig.json file to es5.

Launch the app in dev mode.

cd RichEditor
ng serve

By now you should have the regular first page of any Angular app you create with the CLI.

Setting Up the Text Editor

Our editor page is going to have the following:

  • An input box for the title.
  • The CKEditor 5 balloon editor element.
  • A submit button that only displays when the above two fields have been populated.

In order to speed things up and minimize styling frustrations, we are going to make use of bootstrap. I am by no means a bootstrap expert, in fact, I don’t use it. So pardon me if I do things a bit inefficiently here.

Adding bootstrap

Install bootstrap and some of its dependencies with the command below.

npm install --save bootstrap jquery popper

Add the bootstrap styles to your Angular styles in angular.json like so.

The Angular styles loaded at startup

Note that you would have to restart the server to see the effects of bootstrap.

Creating the Editor Page

We are going to create the editor page as the default route for this app. First, we create the editor component that will house all the elements mentioned above.

ng g c Editor

Then add it to the routes as the default route.

The app routes

Of course, that would not cause the page to show up by default so we will make use of <router-outlet> to display the page. Go back to the app.component.html file and replace all its content with <router-outlet>.

This should change the contents of the default page to “editor works”. That’s great. Now for some intended content.

One thing that would be needed to make our work with the content a lot neater and better structured would be the use of an Article type. So let’s quickly add an interface for that. I like to add all my classes and interfaces for type definition in a folder called models located in the src folder. Below is a simple IArticle interface we will be using.

The Article interface

Before we add the editor, let’s set up the input box for the title and the buttons with Angular template-driven forms for speed's sake. Keep in mind that you will need to import the FormsModule in your app module to get this to work.

Just a dash of CSS here.

Some component code to bring it all home.

To add the editor, the first thing would be to install the ckeditor5 angular package. This package contains the CKEditor module that will enable the setup possible. We will also need to install the exact editor we wish to use. In this case, because we want to keep the editor clean and distraction-free, we will be using balloon. Here is the command to install both packages.

npm i --save @ckeditor/ckeditor5-angular @ckeditor/ckeditor5-build-balloon

Add CKEditorModule to the list of imports in the app.module.ts file. Don’t forget to import it from @ckeditor/ckeditor5-angular first.

Next, we need to add the editor itself to our template. In order for us to do that, we need to first import the balloon editor into the editor.component.ts file.

...
import * as BalloonEditor from '@ckeditor/ckeditor5-build-balloon';
...

Create a new field in the EditorComponent class and assign it to the BallonEditor. Once that is done, you would then need to declare the config object as well that will hold all the settings of the editor.

...
Editor = BalloonEditor;
editorConfig = {
placeholder: 'Type the content here!',
};
...

You can find more properties of the config object here.

Note that there is currently a known issue with using the placeholder property in production. I have left it in here for the sake of completeness and because it works well on the dev server. I will come back to remove this note once that issue has been resolved.

Your editor.component.ts file should look like the below now.

To display the editor on the page, simply add the ckeditor tag along with the other attributes between the input element and the button like so.

...
<ckeditor
[config]="editorConfig" [editor]="Editor"
required [(ngModel)]="article.text"
data="" name="text"
></ckeditor>
...

This would cause a simple editor on the page that is clean and distraction free. You can format text and add images by simply highlighting text and using the tooltip.

A screenshot of the editor displaying som lorem ipsum text

If you try to add an image now you will notice a problem right away. The image does not seem to be added and an error is displayed in the console that says “filerepository-no-upload-adapter: Upload adapter is not defined.” That’s exactly right. You need to set up the image upload adapter so CKEditor knows where to upload images you embed to. There are two major ways of doing this and instructions on both can be found here. But you are in luck! I wrote a custom adapter that does exactly that for you with Cloudinary. Let’s see how to set that up.

Adding the Cloudinary image upload adapter

If you read this article before June 2020, take note that section has changed since then. I deprecated ‘ckeditor-cloudinary-uploader-adapter’ in favour of ‘puff-puff’ Which does the same thing and more.

Firstly, head over to Cloudinary and create an account if you haven't already. You can change your assigned cloud name on signup if you wish. Get your cloud name from the dashboard and then follow instructions that can be found here to create an unsigned upload preset. You do not need any addons. You will be needing those two variables soon.

Then, install the package that helps us do this on the fly from npm. Not to worry, it is very lightweight and does not have any dependencies.

npm i --save puff-puff

Once that is done, the next thing you would want to do would be to add a factory function in the editor.component that CKEditor uses in creating the upload adapter on the fly, using the package you have just installed.

...import { CloudinaryUnsigned } from 'puff-puff/CKEditor';...imagePluginFactory(editor) {
editor.plugins.get( 'FileRepository' ).createUploadAdapter = ( loader ) => {
return new CloudinaryUnsigned( loader, <your_cloud_name>, <your_unsigned_upload_preset>); };}
...

Once that is done, add the factory function as the only element of the extraPlugins array. extraPlugins is a property of the editorConfig object we added earlier.

editorConfig = {
placeholder: 'Type the content here!',
extraPlugins: [ this.imagePluginFactory ],
};

Your editor.component.ts file should now look like the below.

And that’s it. You should be able to upload images now. Complete with an upload progress bar and a tick when the image has been successfully uploaded.

But there is one more thing. The images would not be responsive. To manage that, all we need to do is add one last property to the CloudinaryUnsigned constructor. This should be an array of numbers that represent image sizes we want CKEditor to use in supporting image responsiveness. Keep in mind that this must be done from the smallest size to the largest, and sizes are in pixels. Here is how.

Now we have support for responsive images. Go ahead and add some images to the text area. Wait for the images to upload and head over to your Cloudinary dashboard, you should be able to see the images that have been uploaded.

Puff-Puff can also help with uploading the image to a custom backend service. All you need is an upload URL from the backend service. See more on that here.

Submitting the Form

The last thing for us to do here would be to submit the form and send the data to a new route for displaying. Ideally, you may want to send the new article to a backend server for storage or something of that nature.

Create a new Route and Component

Generate a new component and call it “View”. Add a new route with a path “view” to the app routes and use the newly created ViewComponent as its component.

ng g c view

Displaying the new Article in the View Route

In the onSubmit function of the editor.component.ts file, navigate to the view route and pass along the new article as the NavigationExtra’s state. You would need to inject the Angular router for this to work.

onSubmit() {
this.router.navigate(['/view'], { state: this.article});
}

To display the article content, here is what the view.component.html file should look like.

You would see that we are still making use of the ckeditor element there to render the content of the article. That is exactly right. We could use a div or a paragraph, and that would render the content, but there would be no support for image responsiveness. It is important however to set the disabled property to true so the content is not editable.

While the view.component.ts file should look like this.

There we have it. We have been able to learn how to do the following in this article:

  • Setup CKEditor5 balloon editor
  • Setup a simple Cloudinary image upload adapter for CKEditor
  • Add support for responsive images
  • Display the rich text content on a browser page

Thanks for reading!

If you find errors, please drop a private note and I will address it as soon as possible. Thanks 😄

--

--