2013-03-07 91 views
11

使用MVC 4与KnockoutJS。我可以将不显眼的验证与自定义敲除绑定绑定吗?我目前正在使用afterRender的模板重新验证验证。我很想让它自动添加绑定。像这样:使用定制的KnockoutJS绑定绑定不显眼的验证

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); 
     } 
     }); 
    } 
    }); 
} 
+0

我不得不处理这个问题,我想,也许我可以挖掘我是如何接近这个的。 – kamranicus 2013-03-29 17:48:37

+0

好吧,我从来不需要创建任何自定义验证绑定,我们使用MVC的属性来输出验证属性,并且在进行AJAX调用时也使用'parseDynamicContent'辅助方法。 通过jquery.unobtrusive.js查看,我确定有一种方法可以调用来动态添加规则。 – kamranicus 2013-03-29 18:05:05

回答

3

有趣的问题!这里有一个纯KnockoutJS + VanillaJS解决方案。可能会有一些皱纹,跨浏览器的东西(我看着你,IE!),和粗糙的边缘。如果您喜欢,请在评论中告诉我或提出更新。


视图模型&验证规则:
验证规则应接近视图模型的属性,就像在.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