【问题标题】:onDblclick of a directive: toggle its boolean attribute valueonDblclick 指令:切换其布尔属性值
【发布时间】:2014-09-12 22:52:02
【问题描述】:

我有一个名为 contentEditable 的指令,它也引用了 html5 attr ::docs::

<p  contentEditable="{{edit}}" ng-model="pages.title">default</p>

在指令的 dblclick 上,我希望 contentEditable 的值切换到 true;在模糊切换到false..

我一直在尝试,但是双击无法正常工作。 不确定如何使它按我想要的方式运行。

check out the JSfiddle

var app = angular.module('morningharwoodApp');
app.directive('contenteditable', function() {
  return {
  require: 'ngModel',
  scope:  {
    edit: '@'
  },
  controller: function($scope) {
    $scope.edit = false;
    console.log($scope.edit);
  },
  link: function(scope, elm, attrs, ctrl) {
    // view -> model
    elm.bind('blur', function() {
        scope.$digest(function() {
            ctrl.$setViewValue(elm.html());
        });
    });

    // model -> view
    ctrl.render = function(value) {
        elm.html(value);
    };

    // load init value from DOM
    ctrl.$setViewValue(elm.html());



    elm.bind('dblclick', function(event) {
        scope.edit = !scope.edit;
        console.log(scope.edit);


       console.log('keydown ' + event.which);
       var esc = event.which === 27,
           enter = event.which === 13,
           el = event.target;

       if (esc || enter) {
               // console.log('esc');
               ctrl.$setViewValue(elm.html());
               scope.editable = false;
               el.blur();
               event.preventDefault();                        
       }

      });

    }
  };
});

【问题讨论】:

  • 虽然相当混乱,但代码似乎在 Chrome 上运行良好。有什么问题?
  • 双击确实有效,但单击后直接进入可编辑状态。这很奇怪.. html5 中的 contentEditable 有一个 onclick 事件......我不知道这是否可能:c
  • 所以你想只在双击打开编辑模式是的?
  • @MatthewHarwood:当然是大声笑。 contenteditable 是一个 HTML5 属性。您应该为它使用不同的名称。

标签: javascript html angularjs angularjs-scope angular-directive


【解决方案1】:

您错误地使用了作用域绑定,隔离作用域绑定用于绑定指令作用域和父控制器作用域之间的值,而不是属性本身。

您的原始代码的结果是标签将始终存在并且没有这样的值:

<div contenteditable ng-model="fName"> ..

这就是为什么元素总是可编辑的。

如果要更改属性的值,可以改用attrs.$set()。并且在启用contenteditable后,您必须手动聚焦元素,否则需要再次单击才能进入编辑模式。

elm.bind('dblclick', function () {
  if (!attrs.contenteditable) {
    attrs.$set('contenteditable', true);
    elm[0].focus();
  }
});

然后重新设置模糊属性:

elm.bind('blur', function () {
  attrs.$set('contenteditable', false);

  scope.$apply(function () {
    ctrl.$setViewValue(elm.html());
  });
});

你的ENTER/ESC 关键逻辑也应该在keyup 事件中

elm.bind('keyup', function (event) {
  var esc = event.which === 27,
    enter = event.which === 13;

  if (esc || enter) {
    event.preventDefault();
    elm[0].blur();
  }
});

请参阅下面编辑的 jsfiddle 以获取完整的工作示例。

JSFiddle: http://jsfiddle.net/hMrTA/1/

【讨论】:

  • 嘿,我已经接受了答案是无论如何都要使用 $digest 和 $apply 吗?我刚刚了解了其中的区别,我很好奇如何为此进行优化。否则,很好的答案!
  • 我很高兴能帮上忙 :) $apply 可以接受一个函数/表达式,该函数/表达式将根据作用域进行评估,然后它将调用 $rootScope.$digest()。因此,如果不需要将任何代码传递给$apply(),则运行$scope.$digest() 会比$scope.$apply() 快一点,因为前者只会触发当前$scope 及其子级的观察者,而后者会触发整个 $scope 链 ($rootScope) 上的观察者。但是,几乎在大多数情况下,差异不应该那么显着,但在一些罕见的性能瓶颈中,它应该会有所帮助。
  • nm.. 它确实更新了它,只是没有更新我映射到的不同范围.. 大声笑 nm
  • 忘了提到 $scope.$digest() 如果在具有隔离作用域的指令中使用将不起作用,因为它不会触发它绑定到的父作用域的观察者。可能还有一些类似的情况,所以如果你想使用$scope.$digest()进行微优化,你应该小心。
【解决方案2】:

即使单击一下也可以编辑输入,这是因为您使用焦点元选择器来突出显示它。您可以通过单击(也包括双击)并在键盘上点击 Tab 直到它被选中来实现焦点状态,我相信这比您想要的要多。

我建议重新考虑您的指令。一种想法是有 2 个字段:一个标签(显示当前值)和一个输入字段(允许编辑),并且根据您使用的标志仅显示一个。在标签上绑定 dblclick 事件以更改标志(并显示输入)并在输入上绑定模糊事件以将其切换回来。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-02
    • 2012-05-01
    • 1970-01-01
    • 2017-09-27
    • 2021-02-24
    • 2012-07-21
    • 2011-06-03
    • 1970-01-01
    相关资源
    最近更新 更多