我在通过NgForangular@2.0.0-alpha.44动态添加的CKEditors遇到问题。

Live demo is available here.

@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);
    }
}


您会看到三个正常工作的CKEditor。然后单击底部的“添加”按钮,它将中断容器中的最后一个CKEditor,您甚至可以对其进行写入,并且如果按下任何工具栏按钮,它将引发:

Uncaught TypeError: Cannot read property 'getSelection' of undefined

有趣的是,只有最后一个CKEditor损坏了,其他两个起作用了。似乎Angular2以某种方式操纵了最后一个破坏CKEditor的元素。

我记得使用相同的方法在angular@2.0.0-alpha.35中添加新的CKEditor,我认为它在那里起作用,但是也许我没有注意到。版本angular@2.0.0-alpha.47 is the same

最佳答案

由于使用了wysiwygarea插件,因此您的集成使用Classic CKEditor,从而可以在<iframe>中进行编辑(即避免CSS与网页冲突)。

这种实现的缺点是,一旦您从DOM分离(并重新附加)了此类<iframe>(就像Angular每次添加新的item一样),其内部的document就会“损坏”。破坏是指document.body是从头开始加载的,丢失了您的内容,CKEditor引导程序代码,JS引用等,最终使整个编辑器实例无用。

因此,问题在于呈现此视图的方式:

@View({
    directives: [NgFor, CKEditor],
    template: `
      <div *ng-for="#item of items">
        {{ item }}: <textarea>{{ item }}</textarea>
      </div>
      <button (click)="addItem()">Add</button>`
})


我看到了针对该问题的三种解决方案:


干净的解决方案:添加新项目时,强制Angular不要重新渲染整个items集合。
棘手的解决方案:使用Inline CKEditor,它在<div contenteditable="true" /> div中而不是在<iframe>...<body contenteditable="true" /></iframe>中工作,并且不受DOM突变的影响。
缓慢而缓慢的解决方案:坚持当前的集成,但是在添加新项目之前销毁所有CKEDITOR.instancesinstance.destroy()),然后重新初始化它们CKEDITOR.replace()

09-30 14:24
查看更多