Knockout验证valueUpdate取决于属性错误

时间:2016-01-25 16:06:35

标签: knockout.js knockout-validation

可以从" onblur"更改属性valueUpdate。 to" keyup"取决于属性是否附加了错误?

我想模仿jQuery验证中验证的方式,首先对模糊进行验证,然后对keyup进行验证。

这可能吗?

编辑: 让我澄清并举例说明。我不介意在" keyup"上发生对模型的绑定,我记得的是,即使有机会完成输入,也会向用户显示错误消息。相反,如果我以验证电子邮件地址为例。如果用户键入无效的电子邮件,我希望错误显示在模糊上,如果用户再次将焦点放在字段上以纠正错误,我希望错误在纠正错误后消失。另一方面,如果用户输入有效的电子邮件,然后引入错误,则应立即显示错误。

第二次编辑: 所以我已经考虑过了,我认为验证不应该干扰模型绑定,而是应该对错误消息的显示进行更改。如上所述,我希望错误在错误发生后立即出现,但只有在相关字段发生更改事件后才会出现。

我做了这个几乎的小提琴,但它应该准确显示我想要完成的事情。

http://jsfiddle.net/mntm1bne/3/

<div data-bind="validationOptions: {messageTemplate: 'myCustomTemplate'}">    
    <input data-bind="value: firstName, valueUpdate: 'keyup', event: {change: firstName.enableD}" />
    <br />
    <input data-bind="value: lastName" />

    <div data-bind="if: firstName.isD">
        Firstname is dirty!
    </div>

    <pre data-bind="text: ko.toJSON($data, null, 2)"></pre>
    <div data-bind="text: ko.toJSON($data)"></div>
</div>
<script type="text/html" id="myCustomTemplate">
    <span data-bind="visible: field.isD && !field.isValid(), attr: { title: field.error }">X</span>
</script>

ko.extenders.trackChange = function(target, track) {
  if (track) {
    target.isD = ko.observable(false);
    target.enableD = function() {
        console.log("enable!");
      target.isD(true);
    }
  }
  return target;
};

var ViewModel = function () {
    var self = this;
    self.firstName = ko.observable().extend({ trackChange: true, required: { message: "firstName" }, number: true,
    min: 0,
    max: 100
    });
    self.lastName = ko.observable().extend({ required: { message: "lastName" }});  
}

var viewModel = new ViewModel();

ko.applyBindings(viewModel);

具体来说,错误在于第一个验证消息,即在页面加载时显示。

1 个答案:

答案 0 :(得分:0)

要正确地执行此操作,您需要重写valueUpdate绑定以使其具有可观察性,并且您的observable将基于该值是否有错误。

这听起来很难,所以我选择了一些有点hackier的东西。我为event替换了valueUpdate绑定。它在keydown上触发,如果验证的变量无效,则从输入更新其值(使用event.target)。该值将始终在模糊时更新,因此我无需处理。

var viewModel = {
  num1: ko.observable(50).extend({
    number: true,
    min: 0,
    max: 100
  }),
  maybeEvaluate: function(data, event) {
    setTimeout(function() {
      if (!viewModel.num1.isValid()) {
        viewModel.num1(event.target.value);
      }
    }, 0);
    return true;
  }

};

ko.applyBindings(viewModel);
.validationMessage {
  color: Red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout-validation/2.0.3/knockout.validation.min.js"></script>
0-100:
<input data-bind="value: num1, event: {keydown: maybeEvaluate}" />
<span class="validationMessage" data-bind="validationMessage: num1"></span>
<br />
<input />

这是另一种基于protected observables的方法。受保护的可观察对象的原始设计是为您提供提交或重置更改的选项。我有一个事件强制提交模糊,并且受保护被修改为在当前值无效时接收新值时自动提交。 (我不需要重置例程,因此我将其解析出来,因此请注意protectedObservable定义是自定义的。)

更新根据您的评论(以及我没有包含所需的库),我更新了第二个示例,以便在该字段发生错误时它变得不断有效。

ko.protectedObservable = function(initialValue) {
  //private variables
  var _actualValue = ko.observable(initialValue),
    _tempValue = initialValue,
    hasHadError = false;

  //computed observable that we will return
  var result = ko.computed({
    //always return the actual value
    read: function() {
      return _actualValue();
    },
    //stored in a temporary spot until commit
    write: function(newValue) {
      _tempValue = newValue;
      if (!result.isValid()) {
        hasHadError = true;
      }
      if (hasHadError) {
        result.commit();
      }
    }
  }).extend({
    notify: "always"
  });

  //if different, commit temp value
  result.commit = function() {
    if (_tempValue !== _actualValue()) {
      _actualValue(_tempValue);
    }
  };

  return result;
};

var viewModel = {
  num1: ko.protectedObservable(50).extend({
    number: true,
    min: 0,
    max: 100
  })
};

ko.applyBindings(viewModel);
.validationMessage {
  color: Red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout-validation/2.0.3/knockout.validation.min.js"></script>
0-100:
<input data-bind="value: num1, valueUpdate: 'input', event: {blur: num1.commit}" />
<span class="validationMessage" data-bind="validationMessage: num1"></span>
<br />
<input />