Угловой и динамически добавленный перерыв CKEditors

У меня проблема с динамически добавленными CKEditors, визуализируемыми через NgFor с [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);
    }
}

Вы можете увидеть три корректно работающих редактора CKEditor. Затем нажмите кнопку «Добавить» внизу, и он разбивает последний CKEditor в контейнере таким образом, что вы даже можете писать в него, и если вы нажмете любую кнопку на панели инструментов, он выдает:

Uncaught TypeError: Cannot read property 'getSelection' of undefined.

Интересно, что ломается только последний CKEditor, остальные два работают. Похоже, что Angular2 каким-то образом манипулирует последним элементом, который ломает CKEditor.

Я помню, как использовал тот же способ добавления новых CKEditors в [email protected], и я думаю, что там это сработало, но, возможно, я просто не заметил. Версия [email protected] такая же.


person martin    schedule 02.12.2015    source источник


Ответы (2)


В вашей интеграции используется Classic CKEditor из-за wysiwygarea плагина, который позволяет редактировать в <iframe> (т.е. чтобы избежать столкновения CSS с веб-страницей).

Недостатком такой реализации является то, что как только вы отсоединяете (и снова присоединяете) такой <iframe> от DOM (как 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.instances (instance.destroy()) перед добавлением нового элемента, а затем повторно инициализируйте их CKEDITOR.replace().
person oleq    schedule 03.12.2015

Эта проблема была исправлена ​​в beta-15, см.:

http://plnkr.co/edit/X5whPqDhLS6RjTR2N8hT?p=preview

person martin    schedule 19.04.2016