
How to integrate ckEditor in AngularJS
Good day, dear Khabrovites.
For several months now I have been actively using AngularJS in one of the working projects. I will not sing “laudable songs” or raise this framework because there are no ideal things (and it would probably be very boring to live in a world with such things that do not leave you unable to overcome their shortcomings with your “creativity”). I can only say a few words about the results: the ideology of AngularJS does a very good job of organizing the code in my face and gives the magic tool Directives. By the way, recently there was already a note about CornerJS , in which directives are displayed in the technology center, and this year on Google I / O slipped news about the possible support of custom-elements(not just tags, but complex html components embedded in the page).
At the next stage of development, the question arose about integration with an advanced WYSIWYG editor and my eyes fell on ckEditor right away , since I had already used it several times as part of projects based on DotNetNuke and my impressions were very positive (well, or put it another way: strong flaws in the component was not found and integration took a matter of hours).
Calling Google for pleas for help in integration magic, I got several links to Stackoverflow and other private blogs, where the pasteState event is the solution to all problems and the directive as a whole looks simple and accessible:
But after the next mailstone and deployment, the customer began to notice that sometimes the edited text is not fully saved or the component crashes altogether with Access Violation, in the case of earlier versions of InternetExplorer (<9). The problem was reproduced, the ideal conditions were obtained, and I went to look for a solution to the problem.
After re-reading the documentation and poking the page for the general picture, I came to the conclusion that this event works fine with the keyboard, but completely ignores the insertion of elements (be it text, pictures, etc.) from the plug-ins that come with the kit. It was immediately decided to look for a new event that is more global in nature. But the search results led to this “non-Orthodox” method, which is also a plugin in the appendage (and this is fraught with migration or updates of ckEditor itself). Therefore, it was decided to raise the editor version to the latest available (CKEditor 4.2.1 at that time), risking stability and getting a magic change event at the level of the native api (maybe they just integrated the aforementioned plug-in into the kernel, I honestly did not follow the history). Replacing the event with change helped solve the issue of saving the changed content, but did not solve the problem with Access Violation.
Taught by the bitter popup experiencewindows for IE <9 (IE carries the execution of different windows, to different threads with a complete reset of cookies, etc.) I came to the conclusion that the problem is in the iframe component and the sequence of creating and accessing it inside ckEditor itself, as well as the life cycle scope within AngularJS. The problem is that the CKEDITOR.replace (...) method works unsynchronously in old IEs and “letting go” of the execution context AngularJS tries to bind the model and call setData , which tries to access the still not prepared iframe, which causes Access Violation. I didn’t come up with anything “better” and “more reliable” than the queue, so the result was the following directive code:
There are ambiguous moments in the code related to the queue and values of model. $ ViewValue (in particular, these were attempts to deal with the fading of a component in modal dialogs, which was solved by the twitter bootstrap modal component patch, but this is another story).
Also, I did not fully disclose the moments associated with setData (..., callback), which in fact is one of the synchronizing mechanisms, but, it seems to me, the code looks informative in this context and replaces the words.
I will once again listen to suggestions and criticism about this approach.
PS A
working example of what happened with me http://jsfiddle.net/jWANb/2/ A
working example of what is advised on the Internet http://jsfiddle.net/fvApg/1/
Try to insert a picture in the second example and look at the “result html”. It will be seen that the context has not changed.
For several months now I have been actively using AngularJS in one of the working projects. I will not sing “laudable songs” or raise this framework because there are no ideal things (and it would probably be very boring to live in a world with such things that do not leave you unable to overcome their shortcomings with your “creativity”). I can only say a few words about the results: the ideology of AngularJS does a very good job of organizing the code in my face and gives the magic tool Directives. By the way, recently there was already a note about CornerJS , in which directives are displayed in the technology center, and this year on Google I / O slipped news about the possible support of custom-elements(not just tags, but complex html components embedded in the page).
At the next stage of development, the question arose about integration with an advanced WYSIWYG editor and my eyes fell on ckEditor right away , since I had already used it several times as part of projects based on DotNetNuke and my impressions were very positive (well, or put it another way: strong flaws in the component was not found and integration took a matter of hours).
Calling Google for pleas for help in integration magic, I got several links to Stackoverflow and other private blogs, where the pasteState event is the solution to all problems and the directive as a whole looks simple and accessible:
app.directive('ckEditor', [function () {
return {
require: '?ngModel',
link: function ($scope, elm, attr, ngModel) {
var ck = CKEDITOR.replace(elm[0]);
ck.on('pasteState', function () {
$scope.$apply(function () {
ngModel.$setViewValue(ck.getData());
});
});
ngModel.$render = function (value) {
ck.setData(ngModel.$modelValue);
};
}
};
}]);
But after the next mailstone and deployment, the customer began to notice that sometimes the edited text is not fully saved or the component crashes altogether with Access Violation, in the case of earlier versions of InternetExplorer (<9). The problem was reproduced, the ideal conditions were obtained, and I went to look for a solution to the problem.
After re-reading the documentation and poking the page for the general picture, I came to the conclusion that this event works fine with the keyboard, but completely ignores the insertion of elements (be it text, pictures, etc.) from the plug-ins that come with the kit. It was immediately decided to look for a new event that is more global in nature. But the search results led to this “non-Orthodox” method, which is also a plugin in the appendage (and this is fraught with migration or updates of ckEditor itself). Therefore, it was decided to raise the editor version to the latest available (CKEditor 4.2.1 at that time), risking stability and getting a magic change event at the level of the native api (maybe they just integrated the aforementioned plug-in into the kernel, I honestly did not follow the history). Replacing the event with change helped solve the issue of saving the changed content, but did not solve the problem with Access Violation.
Taught by the bitter popup experiencewindows for IE <9 (IE carries the execution of different windows, to different threads with a complete reset of cookies, etc.) I came to the conclusion that the problem is in the iframe component and the sequence of creating and accessing it inside ckEditor itself, as well as the life cycle scope within AngularJS. The problem is that the CKEDITOR.replace (...) method works unsynchronously in old IEs and “letting go” of the execution context AngularJS tries to bind the model and call setData , which tries to access the still not prepared iframe, which causes Access Violation. I didn’t come up with anything “better” and “more reliable” than the queue, so the result was the following directive code:
app.directive('ckEditor', [function () {
return {
require: '?ngModel',
restrict: 'C',
link: function (scope, elm, attr, model) {
var isReady = false;
var data = [];
var ck = CKEDITOR.replace(elm[0]);
function setData() {
if (!data.length) { return; }
var d = data.splice(0, 1);
ck.setData(d[0] || '', function () {
setData();
isReady = true;
});
}
ck.on('instanceReady', function (e) {
if (model) { setData(); }
});
elm.bind('$destroy', function () {
ck.destroy(false);
});
if (model) {
ck.on('change', function () {
scope.$apply(function () {
var data = ck.getData();
if (data == '') {
data = null;
}
model.$setViewValue(data);
});
});
model.$render = function (value) {
if (model.$viewValue === undefined) {
model.$setViewValue(null);
model.$viewValue = null;
}
data.push(model.$viewValue);
if (isReady) {
isReady = false;
setData();
}
};
}
}
};
}]);
There are ambiguous moments in the code related to the queue and values of model. $ ViewValue (in particular, these were attempts to deal with the fading of a component in modal dialogs, which was solved by the twitter bootstrap modal component patch, but this is another story).
Also, I did not fully disclose the moments associated with setData (..., callback), which in fact is one of the synchronizing mechanisms, but, it seems to me, the code looks informative in this context and replaces the words.
I will once again listen to suggestions and criticism about this approach.
PS A
working example of what happened with me http://jsfiddle.net/jWANb/2/ A
working example of what is advised on the Internet http://jsfiddle.net/fvApg/1/
Try to insert a picture in the second example and look at the “result html”. It will be seen that the context has not changed.