Updating textarea value with CKEditor content in Angular JS

为君一笑 提交于 2019-11-27 14:59:37

问题


I am using latest CKEditor (Standard Version) and based on this question , I have implemented an angular directive like this,

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

It's working fine when I am typing something in CKEditor GUI mode, here I am getting the typed content to textarea's ng-model.

But when I am switching to code-editor, it's not getting the updated content even after switch back to GUI. It's required to type something again in graphical mode.

What is wrong with my directive? Or can I extend this directive with some other CKEditor events?

I want add some more events for form submit or something else.

Demo here.


回答1:


Your directive is working well.

There is a plugin called sourcearea that controls the CKEditor behavior while on source mode. I couldn't see any event being fire inside the code of that plugin for handling input. There are though two events that we can use to catch when the CKEditor goes back to GUI mode. The events are ariaWidget and dataReady.

I've updated your example to use the dataReady event, so it updates the textarea when switching back. I also changed the pasteState event to change, as Dan Caragea said it was introduced in version 4.2. Updated fiddle can be found here

One almost-there-solution I found is to listen to the key event and update the model. It is almost there, because it seems the event is only fired for the old key pressed. So the last key is always missing.

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

Anyway, maybe you can figure out from this how to fix the last key problem. It is almost there!

EDIT: updated fiddle link to correct version




回答2:


I know this question has already been answered, but I thought I'd chime in with what I had to do to integrate CKEditor 4.4.4 with angularjs 1.2. Here is my code in 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

For the coffeescript illiterate, here is the compiled 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);
        };
      }
    };
  }
);

Then in the HTML:

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

Now, for an explanation.

I added paste and selection change handlers for completeness, but it turns out the selection change handler was necessary. I discovered that if I selected all and hit delete, then—without taking focus off the editor—submitted the form, the changes where not reflected in the model on submit. The selection change handler solves that problem.

Integrating CKEditor with angularjs is mission critical for my project, so if I find anymore “Gotchas”, I will update this answer.




回答3:


I am hoping the issue is similar to mine. The CK Editor has its own elements that it injects into the DOM and Angular is already rendered so you will need to set up a listener for when it transitions to the code editor. If you are not listening for the change then Angular cannot bind properly because it is unaware of the changes in the DOM. I ran into something similar with tinymce and the modal that pops up.

Here is another resource that is related to my issue




回答4:


For me the answer by @Mjonir74 worked but as soon as i had multiple editor instances on a page and had to also take into consideration the edit mode not just create mode, things started to not work properly when you'd come back to the page containing the editor. Basically in edit mode, first time you'd visit the page, all was fine, text was in the editor as it should. but any successive visits to same page left the editor empty, no text.

Here's the way it worked for me:

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

and i use it as

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

any number of times in a page and it works just fine in all the modes.



来源:https://stackoverflow.com/questions/18917262/updating-textarea-value-with-ckeditor-content-in-angular-js

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!