0

我目前有 2 个指令:

  1. 创建文本框和工具栏 div 的编辑器指令。
  2. 嵌入到编辑器中的粗体按钮

标记

<editor content="text">
  <bold-button>B</bold-button>
</editor>

编辑器指令

.directive('editor', function () {
  return {
    restrict: 'E',
    replace: true,
    transclude: true,
    scope: {
      'content': '='
    },
    template: '<div class="editor">' +
                '<div class="toolbar" ng-transclude></div>' +
                '<textarea ng-model="content"></textarea>' +
              '</div>',
    controller: function ($scope, $element, $attrs) { },
    link: function (scope, elem, attrs, ctrl) {
      var editor = new Editor();
      editor.onPostUpdateDom = function () {
        scope.content = elem.find('textarea').val();
      };
      // Expose editor to other directives
      ctrl.editor = editor;
    };
});

粗体按钮指令

.directive('boldButton', function () {
  return {
    require: '^editor',
    restrict: 'E',
    replace: true,
    transclude: true,
    scope: {},
    template: '<button type="button" ng-click="format()" ng-transclude>'+
              '</button>',
    link: function (scope, elem, attrs, editorCtrl) {
      scope.format = function () {
        editorCtrl.editor.formatCommand("bold");
      };
    };
});

editor指令使用第三方插件,该插件提供了一种formatCommand()更改 textarea 值的方法。

粗体按钮指令通过编辑器的控制器触发此方法

现在,每次插件更改 DOM 时,它都会引发一个onPostUpdateDOM事件,我使用该事件来获取新值并将其分配给编辑器指令中的范围:

scope.content = elem.find('textarea').val();

这真的很好用。按下按钮,值发生变化。

然而,该插件还通过键盘快捷键提供 DOM 操作。当 DOM 被更改时,该scope.content = elem.find('textarea').val();行不起作用,因为它发生在 Angular 之外。将该行包装在一个$apply作品中,但随后formatCommand()来自按钮指令的调用会引发“应用已在进行中”错误。

这是“安全应用”反模式的案例吗?!

4

1 回答 1

0

编辑器指令中的这些行:

editor.onPostUpdateDom = function () {
  scope.content = elem.find('textarea').val();
};

问题是,onPostUpdateDom事件处理程序从 Angular 世界内部或外部触发,并且由于对第三方插件的依赖,它不受开发人员的控制。

为了解决这个问题,我们基本上需要一个安全的应用程序来处理 Angular 和非 Angular 事件:

请参阅:AngularJS:在调用 $scope.$apply() 时防止错误 $digest 已经在进行中

所以答案是将代码包装在一个$timeout.

IE

editor.onPostUpdateDom = function () {
  $timeout(function () {
    // anything you want can go here and will safely be run on the next digest.
    scope.content = elem.find('textarea').val();
  });
};
于 2014-03-31T14:25:43.757 回答