Reputation: 96891
I'm having an issue with dynamically added CKEditors rendred via NgFor
with [email protected]
.
@Directive({
selector: 'textarea'
})
class CKEditor {
constructor(_elm: ElementRef) {
CKEDITOR.replace(_elm.nativeElement);
}
}
@Component({
selector: 'my-app',
})
@View({
directives: [NgFor, CKEditor],
template: `
<div *ng-for="#item of items">
{{ item }}: <textarea>{{ item }}</textarea>
</div>
<button (click)="addItem()">Add</button>`
})
class AppComponent {
items = ['default_0', 'default_1'];
constructor() {
this.addItem();
}
addItem() {
var id = 'ckeditor_inst_' + this.items.length;
this.items.push(id);
}
}
You can see three CKEditors that work correctly. Then click "Add" button at the bottom and it breaks the last CKEditor in the container in a way that you can even write to it and if you press any toolbar button it throws:
Uncaught TypeError: Cannot read property 'getSelection' of undefined
.
It's interesting that only the last CKEditor is broken, the other two work. It seems like Angular2 somehow manipulates with the last element which breaks the CKEditor.
I remember using the same way of adding new CKEditors in [email protected]
and I think it worked there but maybe I just didn't notice. Version [email protected]
is the same.
Upvotes: 2
Views: 1953
Reputation: 96891
This issue has been fixed in beta-15
, see:
http://plnkr.co/edit/X5whPqDhLS6RjTR2N8hT?p=preview
Upvotes: 2
Reputation: 15895
Your integration uses Classic CKEditor because of wysiwygarea
plugin, which enables editing in an <iframe>
(i.e. to avoid CSS collision with the webpage).
The drawback of such implementation is that once you detach (and re–attach) such <iframe>
from DOM (like Angular does each time you add a new item
), its internal document
gets "broken". By broken I mean that document.body
is loaded from scratch, losing your content, CKEditor bootstrap code, JS references, etc. and eventually making the whole editor instance useless.
So the problem lies in the way this view is being rendered:
@View({
directives: [NgFor, CKEditor],
template: `
<div *ng-for="#item of items">
{{ item }}: <textarea>{{ item }}</textarea>
</div>
<button (click)="addItem()">Add</button>`
})
And I see three solutions to this problem:
items
collection when a new item is added.<div contenteditable="true" />
div instead of <iframe>...<body contenteditable="true" /></iframe>
and is immune to mutations in DOM.CKEDITOR.instances
(instance.destroy()
) before a new item is added and then re–initialise them CKEDITOR.replace()
.Upvotes: 3