Skip to content

Instantly share code, notes, and snippets.

@KangHidro
Last active May 29, 2026 07:41
Show Gist options
  • Select an option

  • Save KangHidro/91c8cd9db6453fd8e3c0c489eccc413b to your computer and use it in GitHub Desktop.

Select an option

Save KangHidro/91c8cd9db6453fd8e3c0c489eccc413b to your computer and use it in GitHub Desktop.
Angular component for TinyMCE Editor
import { HttpClient } from '@angular/common/http';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, inject } from '@angular/core';
import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
import { EditorModule } from '@tinymce/tinymce-angular';
import { lastValueFrom } from 'rxjs';
interface TinyMceBlobInfo {
id: () => string;
name: () => string;
filename: () => string;
blob: () => Blob;
base64: () => string;
blobUri: () => string;
}
type OnChangeCallback = (value: string) => void;
type OnTouchedCallback = () => void;
@Component({
// eslint-disable-next-line @angular-eslint/component-selector
selector: 'tinymce-editor',
imports: [EditorModule, FormsModule],
template: `<editor [(ngModel)]="value" (ngModelChange)="onEditorChange($event)" [init]="editorConfig" [disabled]="disabled" (onBlur)="onTouched()"></editor>`,
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TinymceEditorComponent),
multi: true,
},
],
})
export class TinymceEditorComponent implements ControlValueAccessor {
private http = inject(HttpClient);
private cdr = inject(ChangeDetectorRef);
value = '';
onChange: OnChangeCallback = (_value: string) => { return; };
onTouched: OnTouchedCallback = () => { return; };
disabled = false;
editorConfig = {
base_url: '/assets/tinymce',
suffix: '.min',
plugins: 'advlist lists link image media table code codesample searchreplace directionality charmap emoticons visualblocks visualchars fullscreen insertdatetime nonbreaking pagebreak save help',
toolbar: 'blocks removeformat align bold italic underline strikethrough subscript superscript forecolor link image media table outdent indent code searchreplace | fontfamily fontsize bullist numlist blockquote charmap codesample undo redo selectall',
height: 300,
menubar: true,
paste_as_text: false,
paste_block_drop: false,
paste_data_images: true,
images_upload_handler: async (blobInfo: TinyMceBlobInfo): Promise<string> => {
/*
BE request: form-data: file
BE response: { location: 'url_ảnh_vừa_upload' }
*/
const formData = new FormData();
formData.append('file', blobInfo.blob(), blobInfo.filename());
const uploadUrl = 'https://api.yourserver.com/upload-endpoint';
try {
const response = await lastValueFrom(this.http.post<{ location: string; }>(uploadUrl, formData));
if (response?.location) {
this.cdr.markForCheck();
return response.location;
}
throw new Error('Server response missing location');
} catch (error: unknown) {
if (error instanceof Error) {
console.error(error.message);
}
throw error;
}
},
};
writeValue(val: unknown): void {
this.value = typeof val === 'string' ? val : '';
this.cdr.markForCheck();
}
registerOnChange(fn: OnChangeCallback): void {
this.onChange = fn;
}
registerOnTouched(fn: OnTouchedCallback): void {
this.onTouched = fn;
}
setDisabledState?(isDisabled: boolean): void {
this.disabled = isDisabled;
this.cdr.markForCheck();
}
onEditorChange(newValue: string): void {
this.value = newValue;
this.onChange(newValue);
this.cdr.markForCheck();
}
}
  1. Install packages: npm install @tinymce/tinymce-angular tinymce

  2. Setup angular.json:

{
  "projects": {
    "your-app-name": {
      "architect": {
        "build": {
          "options": {
            "assets": [
              "src/favicon.ico",
              "src/assets",
              {
                "glob": "**/*",
                "input": "node_modules/tinymce",
                "output": "/assets/tinymce/"
              }
            ],
            "scripts": [
              "node_modules/tinymce/tinymce.min.js"
            ]
          }
        }
      }
    }
  }
}
  1. Create component: See angular-tinymce-self-host.ts

  2. Use:

<tinymce-editor [(ngModel)]="varName" />
...
<tinymce-editor formControlName="formcontrol" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment