web-dev-qa-db-ja.com

Angular JSのCKEditorコンテンツでtextarea値を更新する

私は最新のCKEditor(標準バージョン)を使用しており、これに基づいて 質問 、このような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 GUIモードで何かを入力しているときは正常に機能しています。ここでは、入力したコンテンツをtextareaのng-modelに取得しています。

しかし、コードエディターに切り替えると、GUIに切り替えても更新されたコンテンツが取得されません。グラフィカルモードで何かをもう一度入力する必要があります。

私の指令の何が問題になっていますか?または、このディレクティブを他のCKEditorイベントで拡張できますか?

フォーム送信などのイベントをさらに追加したいと思います。

デモはこちら

14
devo

あなたの指令はうまく機能しています。

ソースモードでのCKEditorの動作を制御するsourceareaというプラグインがあります。入力を処理するためのプラグインのコード内でイベントが発生しているのを確認できませんでした。ただし、CKEditorがGUIモードに戻ったときにキャッチするために使用できるイベントは2つあります。イベントはariaWidgetdataReadyです。

dataReadyイベントを使用するように例を更新したので、元に戻すとtextareaが更新されます。また、pasteStateイベントをchangeに変更しました ダンカラガは言った それはバージョン4.2で導入されました。 更新されたフィドルはここにあります

私が見つけたほぼ解決策の1つは、keyイベントをリッスンしてモデルを更新することです。古いキーが押された場合にのみイベントが発生するように見えるため、ほぼそこにあります。したがって、最後のキーは常に欠落しています。

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

とにかく、多分あなたはこれから最後の重要な問題を修正する方法を理解することができます。もうすぐです!

編集:正しいバージョンに更新されたフィドルリンク

27
Jonas

私はこの質問がすでに回答されていることを知っていますが、CKEditor4.4.4をangularjs1.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>

さて、説明のために。

完全を期すために貼り付けと選択変更ハンドラーを追加しましたが、選択変更ハンドラーが必要であることがわかりました。すべてを選択して削除を押した後、エディターからフォーカスを外さずにフォームを送信すると、変更が送信時にモデルに反映されないことがわかりました。選択変更ハンドラーはその問題を解決します。

CKEditorをangularjsと統合することは私のプロジェクトにとってミッションクリティカルなので、「Gotchas」が見つかったら、この回答を更新します。

9
Mjonir74

私はこの問題が私のものと似ていることを望んでいます。 CK Editorには、DOMに挿入する独自の要素があり、Angularは既にレンダリングされているため、コードエディターに移行するときのリスナーを設定する必要があります。聞いていない場合変更の場合、AngularはDOMの変更を認識していないため、正しくバインドできません。tinymceとポップアップするモーダルに似たものに遭遇しました。

これが私の問題に関連する別のリソースです

0
dasper

私にとっては@ 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>

ページ内で何度でも使用でき、すべてのモードで問題なく機能します。

0
Twisted1919