Обновление значения 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?
Я хочу добавить еще несколько событий для отправки формы или чего-то еще.
Демо здесь.
Ответы
Ответ 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>
любое количество раз на странице, и оно работает отлично во всех режимах.