Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
506 views
in Technique[技术] by (71.8m points)

angular - Using Tinymce in Angular2 project

I'm trying to embed tinymce into my website which is built using Angular2. Following is my component:

export class myComponent implements OnInit {
    //some code

    constructor(private af: AngularFire) {
    // some code
    }

    ngOnInit():any {
    tinymce.init(
        {
            selector: ".tinymce",
        });
    }
}

And in side my html, there is:

<textarea class="tinymce" rows="15"></textarea>

But there is error saying "Cannot find name 'tinymce'" but I have already include

<script src='//cdn.tinymce.com/4/tinymce.min.js'></script>

inside the head of html. Did I do something wrong? Is my initialization incorrect?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Here's what I've used for myself, on RC6. First I'll show the usage:

<h1>The Editor</h1>
<textarea htmlEditor [(ngModel)]="txt"></textarea>
<h1>The HTML Source</h1>
<textarea [(ngModel)]="txt"></textarea>
<h1>The Rendered HTML</h1>
<div [innerHTML]="txt"></div>

So the usage is pretty simple and straightforward, the HTML result of the editor is moved to the value of the textarea (I trigger the update on blur event)

And here's the directive definition (Typescript):

import {
    Directive,
    OnDestroy,
    AfterViewInit,
    Provider,
    forwardRef,
    HostBinding
} from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
import { DomSanitizer } from '@angular/platform-browser';

declare var tinymce: any;

export const TinyMceValueAccessor: Provider = {
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => TinyMceDirective2),
    multi: true
};

// Tinymce directive
@Directive({
    selector: '[htmlEditor]',
    providers: [TinyMceValueAccessor]
})

export class TinyMceDirective2 implements OnDestroy, AfterViewInit, ControlValueAccessor {
    static nextUniqueId = 0;
    @HostBinding('attr.data-tinymce-uniqueid') uniqueId;

    onTouchedCallback: () => void = () => { };
    onChangeCallback: (_: any) => void = () => { };
    innerValue;
    init = false;

    constructor(private sanitizer: DomSanitizer) {
        this.uniqueId = `tinymce-host-${TinyMceDirective2.nextUniqueId++}`;
    }

    //get accessor
    get value(): any {
        return this.innerValue;
    };

    //set accessor including call the onchange callback
    set value(v: any) {
        if (v !== this.innerValue) {
            this.innerValue = v;
            this.onChangeCallback(v);
        }
    }

    ngAfterViewInit(): void {
        console.log('tinymce');
        tinymce.init({
            selector: `[data-tinymce-uniqueid=${this.uniqueId}]`,
            schema: 'html5',
            setup: ed => {
                ed.on('init', ed2 => {
                    if (this.innerValue) ed2.target.setContent(this.innerValue);
                    this.init = true;
                });
            }
        });

        // I chose to send an update on blur, you may choose otherwise
        tinymce.activeEditor.on('blur', () => this.updateValue());
    }

    updateValue() {
        const content = tinymce.activeEditor.getContent();
        this.value = this.sanitizer.bypassSecurityTrustHtml(content);
    }

    writeValue(value): void {
        if (value !== this.innerValue) {
            this.innerValue = value;
            if (this.init && value) tinymce.activeEditor.setContent(value);
        }
    }

    registerOnChange(fn): void {
        this.onChangeCallback = fn;
    }

    registerOnTouched(fn): void {
        this.onTouchedCallback = fn;
    }

    ngOnDestroy(): void {
        if (this.init) tinymce.remove(`[data-tinymce-uniqueid=${this.uniqueId}]`);
    }
}

Some highlights:

  • I'm using NG_VALUE_ACCESSOR to provide for two way binding using ngModel
  • I'm assigning a unique id to a custom attribute on the host element so that tinymce only initializes that specific element and no others.
  • I'm sending value updates only on blur events, but you may use a different strategy, for example using debounce time.
  • I'm using DomSanitizer to bypass sanitization, since tinymce sometimes outputs html which triggers Angular 2 sanitization.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...