2013-03-07 7 views
11

KnockoutJSでのMVC 4の使用。カスタムノックアウトバインディングで目立たない検証をバインドできますか?私は現在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

+0

申し訳ありません、カスタム検証バインディングを作成する必要はありませんでした。MVCの属性を使用して検証属性を出力し、AJAX呼び出し時に 'parseDynamicContent'ヘルパーメソッドを使用しました。 jquery.unobtrusive.jsを見て、ルールを動的に追加するために呼び出すことのできるメソッドがあると確信しています。 – kamranicus

答えて

3

興味深い質問!ここに1つの純粋なKnockoutJS + VanillaJSソリューションがあります。いくつかのしわ、クロスブラウザのもの(私はあなたを見ている、IE!)、そして粗いエッジがあるかもしれません。あなたが好きであれば、私はコメントで知らせるか、答えの更新を提案してください。


のViewModel &検証ルール:
検証ルールは、多くの.NETでの属性のように、ViewModelにの性質に近くなければなりません。 KnockoutJSのドキュメントには、この目的のためにextendersを使用することが推奨されています。 Extenderの

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> 

検証メッセージとここにはマークアップがないので、目立たないと DRY。 (あなたががあなたの検証のための特別なマークアップをしたい場合は、だけvalueは、バインディングを使用してname.errorsのための別々のマークアップを作成することができます。)

カスタムバインディング:
をそしてcustom bindingはただ順番に、だろう:

  1. は、入力フィールドの後にテンプレートを注入します。
  2. データとして観測可能なnameのテンプレートバインディングを適用してください。
  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

関連する問題