使用Angular JS中的CKEditor内容更新textarea值

时间:2013-09-20 12:51:23

标签: javascript angularjs ckeditor angularjs-directive wysiwyg

我正在使用最新的CKEditor(标准版)并基于此 question,我已经实现了像这样的角度指令,

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 GUI模式下输入内容时它正常工作,这里我将输入的内容输入textarea的ng-model。

但是当我切换到代码编辑器时,即使在切换回GUI之后也没有获得更新的内容。需要在图形模式下再次键入内容。

我的指令有什么问题?或者我可以将此指令与其他一些CKEditor事件一起扩展吗?

我想为表单提交或其他内容添加更多事件。

Demo here.

4 个答案:

答案 0 :(得分:27)

你的指示运作良好。

有一个名为 sourcearea 的插件,用于控制源模式时的CKEditor行为。我无法在该插件的代码中看到任何事件被触发以处理输入。虽然有两个事件我们可以用来捕捉CKEditor回归的时间 GUI模式。这些活动是 ariaWidget dataReady

我已更新您的示例以使用 dataReady 事件,因此在切换回时会更新textarea。我还将 pasteState 事件更改为更改,因为版本4.2中引入了Dan Caragea said。  Updated fiddle can be found here

我找到的一个几乎就是解决方案是收听事件并更新模型。它几乎就在那里,因为似乎事件只是针对按下的旧键被触发。所以最后一把钥匙总是丢失。

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

无论如何,也许你可以从中找出如何解决最后一个关键问题。它几乎就在那里!

编辑:更新小提琴链接以更正版本

答案 1 :(得分:9)

我知道这个问题已经得到了解答,但我想我已经完成了将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>

现在,要解释一下。

我添加了粘贴和选择更改处理程序以确保完整性,但事实证明选择更改处理程序是必要的。我发现,如果我选择了all并点击删除,那么 - 无需关注编辑器提交的表单,这些更改不会反映在提交的模型中。选择更改处理程序解决了这个问题。

将CKEditor与angularjs集成对我的项目至关重要,所以如果我再找到“Gotchas”,我会更新这个答案。

答案 2 :(得分:0)

我希望这个问题与我的相似。 CK编辑器有自己的元素,它注入到DOM中,而Angular已经被渲染,所以你需要在它转换到代码编辑器时设置一个监听器。如果您没有收听更改,那么Angular无法正确绑定,因为它不知道DOM中的更改。我遇到了类似于tinymce和弹出模式的东西。

Here is another resource that is related to my issue

答案 3 :(得分:0)

对我来说,@ 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>

页面中的任意次数,并且在所有模式下都能正常工作。