Start trial
Plans & PricingContact Us
Log InStart For Free

How to add images in Angular apps with TinyMCE

November 23rd, 2022

9 min read

Angular and an image icon combined together

Written by

Ebuka Peter Onyebinamma

Category

How-to Use TinyMCE

For applications that handle workflow or task management, content management, or a document management system (DMS), images are indispensable. Why? Because your app’s users need images to communicate. And if you’re using a framework that you’re not familiar with, configuring image upload can become time consuming.

You can save time, though, by making use of image upload functions available in your app’s rich text editor. Most reliable editors provide some kind of Angular image upload functionality, including TinyMCE, which provides an easy-to-use image option.

This how-to guide explains the steps to configure the image upload option using TinyMCE Angular WYSIWYG editor for your app. It covers what can go wrong during the interaction, and the best way to set up your image uploads when connecting TinyMCE with Angular.

TinyMCE can be used within a variety of use cases, including a DMS, Content Management System (CMS), or Workflow management system, and for more information on these use cases:

  1. TinyMCE and DMS 
  2. Using TinyMCE for a CMS 
  3. Workflow and Task management apps with TinyMCE
  4. TinyMCE’s Angular integration.

What is Angular?

Angular is a framework for building dynamic, Single Page Applications (SPAs). It offers a powerful solution for several different use cases. It has adopted the TypeScript programming language, and also offers a solid architecture, modularization, and comprehensive documentation, all of which makes it a powerful and popular framework.

How to set up TinyMCE in Angular

The following sections outline and explain how to:

  1. Set up an Angular 14 project from scratch
  2. Integrate the TinyMCE image upload feature
  3. Deploy the project to a demo server.

Creating your Angular application

To create an Angular application, you need the following:

Before you can move forward in the tutorial, you need to have Angular installed.

  1. Open your terminal and type the command below:

npm install -g @angular/cli
  1. Confirm that Angular has been successfully installed by typing the following command below in your terminal:

ng --version

Confirming that Angular has installed on the command line

  1. Create a folder dedicated to this project, cd to that folder, and run the command below:

ng new "name of the project here"

You'll be asked if you’d like to add routing, to which you should answer yes, and which stylesheet format you'd like to use, to which you should answer CSS.

  1. Confirm that you have successfully created a new Angular project.

Confirming the angular project works on the command line

Set up TinyMCE in Angular

Note: While this article walks you through the steps of configuring TinyMCE, you can also check out the documentation

 

  1. Run the command below to install TinyMCE using npm:

npm install tinymce @tinymce/tinymce-angular
  1. Open the app.module.ts file in your project, and replace the contents there with the code below:

    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    import { EditorModule } from '@tinymce/tinymce-angular';
    import { AppComponent } from './app.component';

    @NgModule({
      declarations: [
        AppComponent
      ],

      imports: [
        BrowserModule,
        EditorModule
      ],

      providers: [],
      bootstrap: [AppComponent]
    })

    export class AppModule { }
  1. Open your template app.component.ts file, located in the app folder. Replace the contents there with the following:

   <h1>TinyMCE 6 Angular Demo</h1>
    <editor
      [init]="{ plugins: 'lists link image table code help wordcount' }"
    ></editor>
  1. Use any text you'd like for the header: open the angular.json file and locate the assets array under the build key.

  2. Add the following entry: { "glob": "**/*", "input": "node_modules/tinymce", "output": "/tinymce/" }.

The `assets’ array should look like this:

   "assets": [
    “src/favicon.ico”,
    “src/assets”,
      { "glob": "**/*", "input": "node_modules/tinymce", "output": "/tinymce/" }
    ]
  1. Start your Angular server and launch your app using the command below:

ng serve --open

The open argument after the "ng serve" command automatically launches the app once the server gets started. When this happens, you'll see the launched app in your default browser. Here’s an example of the server running in Chrome:

TinyMCE running in the browser within an Angular project

Notice there's a warning that the domain isn't registered with Tiny Cloud. To fix and remove that warning, you'll need to get a free API Key.

  1. Go to the TinyMCE website and sign up for free (no credit card required). After you've signed in, you'll be able to access your Tiny API key on your dashboard.

  2. Copy that key, go to your template, the app.component.html file, and add the code snippet below with your API key in the correct place:

   <editor
      apiKey="api key should be here"
      [init]="{ plugins: 'lists link image table code help wordcount' }"
    ></editor>
  1. Save the project and restart your server, and the error message will be gone.

Setting up Firebase

For image upload, a valuable option is the Firebase cloud storage to host your images. Firebase is free, and does not require a credit card to sign up.

  1. On the Firebase website, click Get started and create an account.

  2. With your account created, next you'll create a new project. Navigate to your console, and click on Add Project.

  3. On the next page, you'll need to give your project a name, toggle the box to confirm that you accept the Firebase terms of use, and then click Continue. Optionally, you can enable Google Analytics. Click Create project.

  4. Activate cloud storage – click on Storage in the left navigation bar of your dashboard. You'll get a pop-up that prompts you to select either production or test mode, and to select a location.

Note: Select the test mode for the tutorial. In production, select the production mode, which allows you to easily set rules to ensure the security of your app.

 

  1. Add a web project by clicking on Project Overview in the left navigation bar.

  2. On the overview page, there are three icons: iOS, Android, and web. Note that in some cases, you may not see these icons. In this case, there will be a faded Add App button, which you can click to bring up the platform icons.

  3. Select the web icon to begin adding a web project, which brings up a pop-up to create the project.

  4. Give your app a name and click on register app.

Adding Firebase to your project

  1. Start by installing Firebase on your machine by running the command below:

npm install -g firebase firebase-tools

Note: In the commands above, the -g keyword installs Firebase globally on your machine. Using this command would mean you won’t need to install Firebase in your subsequent projects.

 

  1. Log in to Firebase by running the command below:

firebase login

This command initiates the login process by opening your default browser, where you can log into Firebase.

After you've logged in, you need to connect your local Angular project to Firebase.

Connecting your Angular app to Firebase

Set this up using the Angular backend service AngularFire. This is used by Angular to provide storage and other backend services, such as authentication and deployment. To install:

  1. Run the command below in your terminal:

ng add @angular/fire

During the installation, you'll be prompted to select the Firebase services you want. In this case, the only necessary service is cloud storage. However, if you wish to deploy your app with Firebase, you can select the deploy option, as well. Once you select the services you need, proceed with the installation.

Once AngularFire is installed, you can edit the following files:

  • app.component.html
  • app.component.ts
  • app.module.ts.

Replace the current contents with the appropriate code block, below.

  1. In app.component.html, paste the following content:

<h1>TinyMCE 6 Angular Demo</h1>
    <editor
      apiKey="api key here"
      [init]="config"
      [(ngModel)]="source"
    ></editor>

In the code block above, you have an editor component that has three properties:

  • apiKey: This holds the value of your unique API key.
  • [init]="config": This property passes the configuration from the component class in the app.component.ts file to the editor.
  • [(ngModel)]: This is an Angular directive that binds the user input – in this case, an image or file – and helps to keep track of it.
  1. In app.component.ts, add the following code:

   import { Component, OnInit } from '@angular/core';
    import { EditorComponent } from '@tinymce/tinymce-angular';
    import { AngularFireStorage } from '@angular/fire/compat/storage';
    import { finalize, last } from 'rxjs/operators';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css'],
    })

    export class AppComponent implements OnInit {
      source: string = '';
      title = 'images-tinymce';
      config: EditorComponent['init'] = {
        plugins: 'lists link image table code help wordcount',
        toolbar:
          'undo redo | bold italic | alignleft aligncenter alignright | bullist numlist outdent indent | link image',
        file_picker_types: 'image',
        image_advtab: false,
        image_description: false,
        image_dimensions: false,
        block_unsupported_drop: true,
        placeholder: 'Once upon a time...',
        content_css: 'writer',
        content_style: 'img{max-width:100%;height:auto;}',
        images_reuse_filename: true,
        paste_data_images: false,
        height: 'calc(100vh - 88px)',
        images_upload_handler: (blobInfo) => {
          const file = blobInfo.blob();
          const filePath = `${Date.now()}-${blobInfo.filename()}`;
          const ref = this.storage.ref(filePath);
          const task = this.storage.upload(filePath, file);
          const promise = new Promise<string>((resolve, reject) => {
            task
              .snapshotChanges()
              .pipe(
                finalize(() =>
                  ref
                    .getDownloadURL()
                    .pipe(last())
                    .subscribe((url) => {
                      resolve(url);
                    })
                )
              )
              .subscribe((_) => {
                // do nothing
              });
          });
          return promise;
        },
      };
      constructor(private storage: AngularFireStorage) {} //angular fireStorage gets injected into the component.</
      ngOnInit() { }

    }

In the code above, you have an AppComponent class. It contains a source variable that helps keep track of user input. You also have the config, which holds the TinyMCE configuration for the editor.

In the constructor, just like any other service in Angular, the AngularFireStorage gets injected into the component.

In the config, there's an image_upload_handler that uses the injected instance of AngularFireStorage to upload the image to Firebase storage. Once the upload has completed, the handler returns a promise that resolves to the URL of the uploaded image.

  1. Replace the contents in app.module.ts with the following:

    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core'
    import { EditorModule } from '@tinymce/tinymce-angular';
    import { AppComponent } from './app.component';
    import { FormsModule } from '@angular/forms';
    import { AngularFireModule } from '@angular/fire/compat';
    import { environment } from '../environments/environment';
    import { AngularFireStorageModule } from '@angular/fire/compat/storage';
    @NgModule({
      declarations: [AppComponent],
      imports: [
        BrowserModule,
        EditorModule,
        FormsModule,
        AngularFireModule.initializeApp(environment.firebase),
        AngularFireStorageModule,
      ],
      providers: [
      ],
      bootstrap: [AppComponent],
    })
    export class AppModule {}

Running TinyMCE image upload in a demo server

Test your image upload implementation by restarting your server. Kill the server with the Ctrl + C keyboard combination, and then restart the server with the command below:

ng serve

You can go further by deploying your project live.

In this tutorial, the choice of remote server for deployment is Netlify. If you're new to deploying an Angular app to Netlify, you can read a comprehensive tutorial on how to do so here. Note that if you choose to deploy your app to a remote server, you’ll need to ensure that you register the domain in the Approved Domains tab of your TinyMCE dashboard.

You can see the app deployed on Netlify here. You can also see a short video of the TinyMCE Angular image upload in action here. If you have been following along with the tutorial, you should have the same result.

What can go wrong in an Angular image upload?

Although images can be uploaded in a normal Angular form, there are some common problems that can occur when integrating image upload into your application.

SVG security issues

When you're deciding if you're going to use SVG in your Angular app, it's important you consider the fact that SVG files can pose a serious security threat to an application. This is because an SVG is an XML-based file format, and can have embedded CSS and JavaScript. 

Malicious code contained in JavaScript automatically runs when the web browser finds it embedded within the SVG image XML schema. To avoid this, the TinyMCE plug-in does not support SVG uploads by default.

However, you could allow it by specifying the SVG type in your code, and sanitizing on the server side. However, it’s crucial to sanitize to prevent cross-site scripting attacks, which is a web security vulnerability that allows an intruder to compromise user interactions.

An XSS attack can open the door to many dangerous vulnerabilities. 

A rogue script can access any data that the rest of the webpage has access to, including the user’s cookies, session tokens, and localstorage. This allows the script to impersonate the user and gain access to their sensitive data, which it can send to the attacker using an HTTP request.

Scripts can also be used to maliciously modify the DOM. For example, it might show a login screen to trick the user into entering – and thus give away – their credentials. Using the HTML5 API, a malicious script can access the user’s geolocation, microphone, and even webcam. 

Therefore, protecting against XSS attacks is a critical part of ensuring that users can safely use your site.

Incorrect file pathways

A file path describes where a file or an image is located in a website folder structure. An incorrect file pathway occurs when the location of an image or file is incorrect or absent, which can lead to the image failing to display.

Furthermore, it can take as little as an extra space in your image file path to cause a file pathway error. So, typography errors do matter. Always ensure you specify your assets directory, as well as the subfolder or subfolders in which your image file is located. Check on the example below:

<img src="assets/image/hero.jpg" alt="">

The above snippet specifies a correct file path for the hero image: it's located in the image subdirectory of the assets folder.

Below is an incorrect file path for the hero image, and will fail to display because of the spaces after image:

<img src="assets/image /hero.jpg" alt="">

Angular image upload for your app with TinyMCE

Note: You can find the complete source code for this article in this GitHub repo. Feel free to clone and modify the code to suit your project.

For a more secure image handling experience, set up image upload in your Angular app using the TinyMCE integration. You could potentially combine this with Firebase cloud storage for a good service that you can enlist for image upload.

TinyMCE’s image upload functionality provides a solution for SVG security, and takes care to prevent incorrect file pathways issues, which is what makes the process safer for your customers.

For more information on TinyMCE integrations, reach out to us anytime if you have further questions about TinyMCE’s popular frameworks integrations, such as Angular, Vue, and React.js.

ImagesAngularSecurityTinyMCE
byEbuka Peter Onyebinamma

A Senior Front-end engineer, UX designer, Tech writer, and Tech community builder. An extremely passionate techie, and life long learner – personal tech blog: https://userinterfacecabal.com/

Related Articles

  • How-to Use TinyMCENov 21st, 2024

    What are Line Breaks? Learn How to Add and Remove Them

Join 100,000+ developers who get regular tips & updates from the Tiny team.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Tiny logo

Stay Connected

SOC2 compliance badge

Products

TinyMCEDriveMoxieManager
© Copyright 2024 Tiny Technologies Inc.

TinyMCE® and Tiny® are registered trademarks of Tiny Technologies, Inc.