【问题标题】:Bind unobtrusive validation with custom KnockoutJS binding使用自定义 KnockoutJS 绑定绑定不显眼的验证
【发布时间】:2013-02-22 01:43:30
【问题描述】:

将 MVC 4 与 KnockoutJS 一起使用。我可以将不显眼的验证与自定义敲除绑定绑定吗?我目前正在使用带有afterRender 的模板重新绑定验证。我希望它自动添加到绑定中。像这样:

ko.bindingHandlers.egtZipRep = {
    init: function (element, valueAccessor, allBindingsAccessor, context) {
      $(element).inputmask("99999", { "placeholder": " " });
      egtUniqueNameBinding(element, ++ko.bindingHandlers['uniqueName'].currentIndex);

      applyValidationRules(element); // Is it possible to do this here?

      ko.bindingHandlers.value.init(element, valueAccessor, allBindingsAccessor, context);
    }
};

我整天都在摆弄它。如果效率极低,我就做不到。

我目前的做法如下。也许我应该对此感到高兴。但我猜人们之前已经尝试过。

self.ReferenceAfterRender = function (element) {
    bindUnobtrusiveValidation(element);
}

// Bind validation on new content
function bindUnobtrusiveValidation(element) {
   // Bind to fields - must be called everytime new field is created
   $.validator.unobtrusive.parseDynamicContent(element);
}

$.validator.unobtrusive.parseDynamicContent = function (selector) {
// Use the normal unobstrusive.parse method
$.validator.unobtrusive.parse(selector);

// Get the relevant form
var form = $(selector).first().closest('form');

// Get the collections of unobstrusive validators, and jquery validators
// and compare the two
var unobtrusiveValidation = form.data('unobtrusiveValidation');
var validator = form.validate();

if (typeof (unobtrusiveValidation) != "undefined") {
  $.each(unobtrusiveValidation.options.rules, function (elname, elrules) {
    if (validator.settings.rules[elname] === undefined) {
      var args = {};
      $.extend(args, elrules);
      args.messages = unobtrusiveValidation.options.messages[elname];
      $('[name=' + elname + ']').rules("add", args);
    } else {
      $.each(elrules, function (rulename, data) {
        if (validator.settings.rules[elname][rulename] === undefined) {
          var args = {};
          args[rulename] = data;
          args.messages = unobtrusiveValidation.options.messages[elname][rulename];
          $('[name=' + elname + ']').rules("add", args);
        }
      });
    }
  });
 }

【问题讨论】:

  • 我想我不得不处理这个问题,也许我可以挖掘一下我是如何处理这个问题的。
  • 好吧,我从来不用创建任何自定义验证绑定,我们使用 MVC 的属性来输出验证属性,并且在进行 AJAX 调用时还使用了 parseDynamicContent 辅助方法。浏览 jquery.unobtrusive.js,我确信有一个方法可以调用来动态添加规则。

标签: jquery asp.net-mvc-4 knockout.js unobtrusive-validation


【解决方案1】:

有趣的问题!这是一个纯 KnockoutJS + VanillaJS 解决方案。可能会有一些皱纹、跨浏览器的东西(我在看着你,IE!)和粗糙的边缘。如果您愿意,请在 cmets 中告诉我或建议更新答案。


ViewModel 和验证规则:
验证规则应该接近 ViewModel 的属性,很像 .NET 中的属性。 KnockoutJS 的文档建议为此使用extenders。用法如下所示:

self.name = ko.observable("Bob-Martin");
self.name = self.name.extend({ regex: { pattern: "^[^0-9]*$", message: "No digits plz!" } })
self.name = self.name.extend({ regex: { pattern: "^[^-]*$", message: "No dashes plz!" } });

扩展器代码:
文档中的扩展器既好又简单。这是处理多个验证错误的替代方法(尽管它需要为具有相同消息的多个规则做一些工作):

ko.extenders.regex = function(target, options) {
    options = options || {};
    var regexp = new RegExp(options.pattern || ".*");
    var message = options.message || "regex is mad at you, bro!";

    // Only create sub-observable if it hasn't been created yet
    target.errors = target.errors || ko.observableArray();

    function validate(newValue) {
        var matched = regexp.test(newValue);

        if (!matched && target.errors.indexOf(message) == -1) {
            target.errors.push(message);
        }
        else if (matched && target.errors.indexOf(message) >= 0) {
            // TODO: support multiple extender instances with same 
            // message yet different pattern.
            target.errors.remove(message);
        }
    }

    validate(target()); //initial validation
    target.subscribe(validate); //validate whenever the value changes
    return target; //return the original observable
};

验证消息模板:
为了使视图 DRY 和验证不显眼,我会为验证错误定义一个模板,如下所示:

<script type="text/html" id="validation">
    <span data-bind="foreach: $data" class="errors">
        <span data-bind='text: $data'> </span>    
    </span>
</script>

查看:
实际的视图可以很简单:

<p>Name: <input data-bind='valueWithValidation: name' /></p>

不显眼且干燥,因为这里没有带有验证消息的标记。 (不过,如果您希望使用特殊标记进行验证,可以只需使用 value 绑定并为 name.errors 创建单独的标记。)

自定义绑定:
custom binding 会按顺序执行:

  1. 在输入字段后注入模板。
  2. 使用name observable 作为数据应用正确的模板绑定。
  3. 将其余部分传递给 valuevalueUpdate 绑定。

这里是绑定(可能需要一些重构,不过 jQuery/javascript 喜欢):

ko.bindingHandlers.valueWithValidation = {
    init: function (element, valueAccessor, allBindingsAccessor) {
        // Interception! Add validation markup to the DOM and
        // apply the template binding to it. Some of this code
        // can be more elegant, especially if you use jQuery or
        // a similar library.
        var validationElement = document.createElement("span");
        element.parentNode.insertBefore(validationElement, element.nextSibling);
        ko.applyBindingsToNode(validationElement, { template: { name: 'validation', data: valueAccessor().errors } });

        // The rest of this binding is handled by the default
        // value binding. Pass it on!
        ko.applyBindingsToNode(element, { value: valueAccessor(), valueUpdate: 'afterkeydown' });
    }
};

演示:
要查看所有这些操作,请查看this jsfiddle

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-22
    • 1970-01-01
    • 2012-12-02
    • 2015-07-27
    • 2018-12-24
    • 1970-01-01
    相关资源
    最近更新 更多