Hi I'm trying to implement tinymce into an angular 2 component for a small forum to create a new thread.
I want the content of the textarea (tinymce) be 2-way-binded to a variable inside the component. So far the submit button works but the keyup event doesn't.
export class ForumNewThreadComponent implements OnInit{
constructor(){}
ngOnInit():any {
tinymce.init(
{
selector: ".tinyMCE",
})
}
text:string;
submit(){
this.text = tinymce.activeEditor.getContent();
}
getTinymceContent(){
this.text = tinymce.activeEditor.getContent();
}
}
and view
<div class="thread-body">
{{getValue}}
<textarea class="tinyMCE" style="height:300px" (keyup)="getTinymceContent()">
</textarea>
<button class="btn btn-primary" (click)="submit()">Submit</button>
</div>
I would implement a custom value accessor for this:
const TINY_MCE_VALUE_ACCESSOR = new Provider(
NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => TinyMceValueAccessor), multi: true});
@Directive({
selector: 'textarea[tinymce]',
host: { '(keyup)': 'doOnChange($event.target)' },
providers: [ TINY_MCE_VALUE_ACCESSOR ]
})
export class DateValueAccessor extends DefaultValueAccessor {
@Input()
tinymce:any;
onChange = (_) => {};
onTouched = () => {};
writeValue(value:any):void {
if (value!=null) {
super.writeValue(value.toString());
}
}
doOnChange(elt) {
this.onChange(this.tinymce.activeEditor.getContent());
}
}
I would use it this way:
<textarea [tinymce]="tinymce" style="height:300px" [(ngModel)]="text">
</textarea>
and in your component class:
@Component({
(...)
directives: [ DateValueAccessor ]
})
export class ForumNewThreadComponent implements OnInit{
constructor(){}
ngOnInit():any {
tinymce.init({
selector: "[tinymce]"
})
}
text:string;
}
Or do it like this, using tmce's change event and NgZone
constructor(public zone:NgZone) {}
ngOnInit():any {
tinymce.init(
{
selector: ".tinyMCE",
setup: (ed) => {
ed.on('keyup change', (ed, l) => {
this.zone.run(()=> {
this.text = tinymce.activeEditor.getContent();
});
});
}
})
}
This would fail once you have more than one instance on tmce in one component.
Put this logic in a directive like Thierry's implementation.
I wanted to say I did the same implementation as stated above, but I came across this weird error and banged my head around and around fixing this error of 'cannot modify NodeName of Null'
, so finally today I fixed the error and I wanted to share it, so people won't have to search it anymore what the error might be. I know this is an old post my apologies for that.
- get the code of github (directive). link below.
thankyou @Abhijith Nagaraja for the post.
https://github.com/Abhijith-Nagaraja/tinymce-docs/blob/master/integrations/angular2.md#sample-directive-implementation-with-ngmodel-two-way-binding
2.
add two variables to the directive
private editor;
private init: boolean = false;
rewrite the method
writeValue(value: any): void {
// ...
}
to
writeValue(value: any): void {
// This check is necessary because, this method gets called before editor gets initialised.
// Hence undefined/null pointer exceptions gets thrown
if (this.init) {
if (tinymce.get(this.selector)) {
tinymce.get(this.selector).setContent(value, {format: 'raw'});
}
}
}
replace in ValueOnChange(change: boolean)
this.val = tinymce.activeEditor.getContent();
to
if (tinymce.activeEditor) {
this.val = tinymce.activeEditor.getContent();
}
rewrite tinymce.init(options)
to
tinymce.init(options).then(() => {
this.init = true;
});
and last add a ngOnDestroy
method
ngOnDestroy() {
tinymce.remove(this.editor);
}
This has fixed the error for me and also fixed for me when the editor was already initialized and I had reuse it, it wouldn't compile. but now because of the ngOnDestroy
I now can destroy the editor and the afterViewInit
will recall the tinymce.init
I know this is a little old post. But after scratching my head for over 2 days. I was finally able to figure this out and thought this might be useful to others. So sharing it here
https://github.com/Abhijith-Nagaraja/tinymce-docs/blob/master/integrations/angular2.md#sample-directive-implementation-with-ngmodel-two-way-binding