将逻辑从视图移动到自定义绑定

时间:2015-02-24 23:51:49

标签: javascript knockout.js

我创建了一个Knockout扩展器,因此我可以轻松地将表单字段恢复为原始值。

我想从我的视角中消除混乱,所以我想改变它:

<div data-bind="if: myObservedValue.hasChanges">
  <a href="#" data-bind="click: myObservedValue.revert">Revert</a>
</div>

这样的事情:

  <a href="#" data-bind="revert: myObservedValue">Revert</a>

我知道我需要创建一个自定义绑定,但我很难找到一个干净的方法:

  1. 只将my observable传递给我的绑定并在内部应用可见绑定(考虑我的可观察扩展名是否有变化)
  2. 结合多个绑定,因为我的还原&#39;绑定将需要使用&#39;点击&#39;并且&#39;可见&#39;绑定
  3. 避免将恢复功能暴露给我的视图
  4. 提前致谢

    &#13;
    &#13;
    ko.extenders.revert = function(target, option) {
      target.revert = function() {
        target(target.previousValue);
        target.hasChanges(false);
      };
    
      target.previousValue = option;
      target.hasChanges = ko.observable(false);
      target.hasChanges.extend({
        rateLimit: 100
      });
      target.subscribe(function(newValue) {
        target.hasChanges(target() != target.previousValue);
      });
      return target;
    };
    
    var Vm = function(initialValue) {
      this.myObservedValue = ko.observable(initialValue).extend({
        revert: initialValue
      });
      this.revert = function() {
        this.revert();
      }.bind(this.myObservedValue);
    
      return {
        myObservedValue: this.myObservedValue,
        revert: this.revert
      }
    
    }
    
    ko.applyBindings(new Vm('Edit me!!!'));
    &#13;
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
    
    <input data-bind="textInput: myObservedValue" />
    <div data-bind="if: myObservedValue.hasChanges">
      <a href="#" data-bind="click: myObservedValue.revert">Revert</a>
    </div>
    &#13;
    &#13;
    &#13;

1 个答案:

答案 0 :(得分:0)

您可以使用applyBindingsToNode函数来包装其他绑定

&#13;
&#13;
ko.extenders.revert = function(target, option) {
  target.revert = function() {
    target(target.previousValue);
    target.hasChanges(false);
  };

  target.previousValue = option;
  target.hasChanges = ko.observable(false);
  target.hasChanges.extend({
    rateLimit: 100
  });
  target.subscribe(function(newValue) {
    target.hasChanges(target() != target.previousValue);
  });
  return target;
};

var Vm = function(initialValue) {
  this.myObservedValue = ko.observable(initialValue).extend({
    revert: initialValue
  });
  this.revert = function() {
    this.revert();
  }.bind(this.myObservedValue);

  return {
    myObservedValue: this.myObservedValue,
    revert: this.revert
  }

}

ko.bindingHandlers["revert"] = {
  init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    var obs = valueAccessor();
    
    ko.applyBindingsToNode(element, { visible: obs.hasChanges, click: obs.revert });
  },
  update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
  }
}

ko.applyBindings(new Vm('Edit me!!!'));
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<input data-bind="textInput: myObservedValue" />
<a href="#" data-bind="revert: myObservedValue">Revert</a>
&#13;
&#13;
&#13;

通过包装textInput绑定以及

,可以一起摆脱锚点

&#13;
&#13;
var oldTextInputInit = ko.bindingHandlers["textInput"].init;

ko.bindingHandlers["textInput"].init = function(element, valueAccessor, allBindings, viewModel, bindingContext) {
  
  var obs = valueAccessor();

  if (obs.revert && obs.hasChanges) {
    var a = element.ownerDocument.createElement('a');
    a.href = '#';

    if ( element.nextSibling ) {
      element.parentNode.insertBefore(a, element.nextSibling);
    } else {
      element.parentNode.appendChild(a);
    }

    ko.applyBindingsToNode( a, { text: 'Revert', visible: obs.hasChanges, click: obs.revert });
  }
  return oldTextInputInit(element, valueAccessor, allBindings, viewModel, bindingContext);
}
&#13;
&#13;
&#13;

您还可以为被覆盖的textInput绑定读取的输入添加另一个自定义绑定,这样您就可以传递模板名称来控制要添加的其他HTML等等。