11

KnockoutJSでMVC4を使用する。目立たない検証をカスタムノックアウトバインディングでバインドできますか?現在、。を使用したテンプレートを使用して検証を再バインドしてい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);
        }
      });
    }
  });
 }
4

1 に答える 1

3

面白い質問です!これが1つの純粋なKnockoutJS+VanillaJSソリューションです。いくつかのしわ、クロスブラウザのもの(私はあなたを見ています、IE!)、そして荒いエッジがあるかもしれません。コメントでお知らせいただくか、必要に応じて回答の更新を提案してください。


ViewModelと検証ルール:
検証ルールは、.NETの属性と同様に、ViewModelのプロパティに近い必要があります。KnockoutJSのドキュメントでは、この目的でエクステンダーを使用することを提案しています。使用法は次のようになります。

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
};

検証メッセージのテンプレート:
View 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です。(ただし、検証に特別なマークアップが必要な場合は、バインディングを使用して、の個別のマークアップを作成できますvaluename.errors

カスタムバインディング:カスタムバインディング
は、次の順序で実行されます。

  1. 入力フィールドの後にテンプレートを挿入します。
  2. nameobservableをデータとして正しいテンプレートバインディングを適用します。
  3. 残りをvaluevalueUpdateバインディングに渡します。

バインディングは次のとおりです(ただし、リファクタリングが必要な場合がありますが、jQuery / javascript lovin'):

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' });
    }
};

デモ:
これらすべての動作を確認するには、このjsfiddleを覗いてみてください。

于 2013-05-18T12:10:30.217 に答える