Подтвердить что ты не робот

Обновление значения textarea с содержимым CKEditor в Angular JS

Я использую последнюю версию CKEditor (стандартная версия) и на основе этого question, я применил такую ​​директиву angular,

var cmsPlus = angular.module('cmsPlus', []);

cmsPlus.directive('ckEditor', function() {
  return {
    require: '?ngModel',
    link: function(scope, elm, attr, ngModel) {
      var ck = CKEDITOR.replace(elm[0]);

      if (!ngModel) return;

      ck.on('pasteState', function() {
        scope.$apply(function() {
          ngModel.$setViewValue(ck.getData());
        });
      });

      ngModel.$render = function(value) {
        ck.setData(ngModel.$viewValue);
      };
    }
  };
});

Он отлично работает, когда я печатаю что-то в режиме графического интерфейса CKEditor, здесь я получаю типизированный контент в textarea ng-model.

Но когда я перехожу к редактору кода, он не получает обновленный контент даже после перехода обратно в графический интерфейс. Он должен был ввести что-то еще в графическом режиме.

Что не так с моей директивой? Или я могу распространить эту директиву на другие события CKEditor?

Я хочу добавить еще несколько событий для отправки формы или чего-то еще.

Демо здесь.

4b9b3361

Ответ 1

Ваша директива работает хорошо.

Существует плагин с именем sourcearea, который управляет поведением CKEditor в режиме источника. Я не видел, чтобы в коде этого плагина было обработано какое-либо событие для обработки ввода. Есть хотя два события, которые мы можем использовать, чтобы поймать, когда CKEditor вернется к Режим графического интерфейса. События ariaWidget и dataReady.

Я обновил ваш пример, чтобы использовать событие dataReady, поэтому он обновляет текстовое поле при переключении. Я также изменил событие pasteState на изменить, поскольку сказал Dan Caragea, который был представлен в версии 4.2.  Обновленный скрипт можно найти здесь

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

var cmsPlus = angular.module('cmsPlus', []);

cmsPlus.directive('ckEditor', function() {
  return {
    require: '?ngModel',
    link: function(scope, elm, attr, ngModel) {
      var ck = CKEDITOR.replace(elm[0]);

      if (!ngModel) return;

      ck.on('instanceReady', function() {
        ck.setData(ngModel.$viewValue);
      });

      function updateModel() {
          scope.$apply(function() {
              ngModel.$setViewValue(ck.getData());
          });
      }

      ck.on('change', updateModel);
      ck.on('key', updateModel);
      ck.on('dataReady', updateModel);

      ngModel.$render = function(value) {
        ck.setData(ngModel.$viewValue);
      };
    }
  };
});

В любом случае, возможно, вы можете понять, как исправить последнюю ключевую проблему. Это почти что!

EDIT: обновленная ссылка на скрипт для правильной версии

Ответ 2

Я знаю, что на этот вопрос уже был дан ответ, но я подумал, что буду перекликаться с тем, что мне нужно было сделать, чтобы интегрировать CKEditor 4.4.4 с angularjs 1.2. Вот мой код в coffeescript:

'use strict'

angular.module 'core', []

.directive 'ckeditor', ->
    require: '?ngModel'
    link: (scope, element, attrs, ngModel) ->
        config =
            # CKEditor config goes here

        editor = CKEDITOR.replace element[0], config

        return unless ngModel

        editor.on 'instanceReady', ->
            editor.setData ngModel.$viewValue

        updateModel = ->
            scope.$apply ->
                ngModel.$setViewValue editor.getData()

        editor.on 'change', updateModel
        editor.on 'dataReady', updateModel
        editor.on 'key', updateModel
        editor.on 'paste', updateModel
        editor.on 'selectionChange', updateModel

        ngModel.$render = ->
            editor.setData ngModel.$viewValue

Для неграмотного coffeescript, вот компилируемый javascript:

'use strict';
angular.module('core', []).directive('ckeditor', function() {
    return {
      require: '?ngModel',
      link: function(scope, element, attrs, ngModel) {
        var config, editor, updateModel;
        config = {
            // CKEditor config goes here
        }
        editor = CKEDITOR.replace(element[0], config);
        if (!ngModel) {
          return;
        }
        editor.on('instanceReady', function() {
          return editor.setData(ngModel.$viewValue);
        });
        updateModel = function() {
          return scope.$apply(function() {
            return ngModel.$setViewValue(editor.getData());
          });
        }};
        editor.on('change', updateModel);
        editor.on('dataReady', updateModel);
        editor.on('key', updateModel);
        editor.on('paste', updateModel);
        editor.on('selectionChange', updateModel);
        return ngModel.$render = function() {
          return editor.setData(ngModel.$viewValue);
        };
      }
    };
  }
);

Затем в HTML:

<textarea ckeditor data-ng-model="myModel"></textarea>

Теперь, для объяснения.

Я добавил обработчики изменения палитры и выбора для полноты, но оказалось, что необходим обработчик изменения выбора. Я обнаружил, что если я выбрал все и удаляю delete, то, не отвлекая редактор, вы отправите форму, изменения которой не отражены в модели на submit. Обработчик изменения выбора решает эту проблему.

Интеграция CKEditor с angularjs является критически важной для моего проекта, поэтому, если я больше нахожу "Gotchas", я обновлю этот ответ.

Ответ 3

Я надеюсь, что проблема похожа на мою. Редактор CK имеет свои собственные элементы, которые он вводит в DOM, и Angular уже отображается, поэтому вам нужно будет настроить прослушиватель, когда он перейдет к редактору кода. Если вы не слушаете изменение, то Angular не может связываться должным образом, поскольку он не знает об изменениях в DOM. Я столкнулся с чем-то похожим на tinymce и модальным, который появляется.

Вот еще один ресурс, связанный с моей проблемой

Ответ 4

Для меня ответ от @Mjonir74 работал, но как только у меня было несколько экземпляров редактора на странице, и также нужно было учитывать режим редактирования, а не только режим создания, все стало работать неправильно, когда вы вернулись на страницу, содержащую редактор. В основном в режиме редактирования, в первый раз, когда вы посетили страницу, все было в порядке, текст был в редакторе так, как должен. но любые последующие посещения на той же странице оставляли редактор пустым, без текста.

Вот как это сработало для меня:

    app.directive('appWysiwygBlock', function() {
    return {
        require: 'ngModel',
        restrict: 'E',
        templateUrl: 'modules/app/templates/directives/wysiwyg-block.html',
        scope: {
            error: '=',
            config: '='
        },
        link: function(scope, element, attrs, ngModel) {

            if (typeof CKEDITOR == 'undefined' || !ngModel) {
                return;
            }

            scope.required = attrs.required || false;
            scope.cols = attrs.cols || 6;

            scope.label = attrs.label || attrs.name;
            scope.name = attrs.name || scope.label;
            if (scope.name) {
                scope.name = scope.name.toLowerCase().replace(/[^a-z0-9]/gi, '_');
            }

            var defaultConfig, config, editor, updateModel;

            config = scope.config || {};
            defaultConfig = {
                customConfig: '/modules/app/ckeditor-config.js'
            };

            config = element.extend({}, defaultConfig, config);
            editor = CKEDITOR.replace(element.find('textarea:first')[0], config);

            updateModel = function() {
                return scope.$apply(function() {
                    return ngModel.$setViewValue(editor.getData());
                });
            };

            editor.on('instanceReady', function() {
                editor.on('change', updateModel);
                editor.on('dataReady', updateModel);
                editor.on('key', updateModel);
                editor.on('paste', updateModel);
                editor.on('selectionChange', updateModel);
                return editor.setData(ngModel.$viewValue);
            });

            return ngModel.$render = function() {
                return editor.setData(ngModel.$viewValue);
            };
        }
    };
});

и я использую его как

<app-wysiwyg-block label="Description" name="description" ng-model="item.description" error="fieldErrors.description" required="true" cols="12"></app-wysiwyg-block>

любое количество раз на странице, и оно работает отлично во всех режимах.