2013-03-07 6 views
11

Verwenden MVC 4 mit KnockoutJS. Kann ich eine unauffällige Validierung mit einer benutzerdefinierten Knockout-Bindung binden? Ich verbinde die Validierung derzeit mit einer Vorlage mit afterRender. Ich würde es gerne mit der Bindung automatisch hinzugefügt haben. Gefällt mir:Binden Sie unauffällige Validierung mit benutzerdefinierten KnockoutJS Bindung

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

Ich habe den ganzen Tag damit herumgebastelt. Ich kann es nicht tun, ohne extrem ineffizient zu sein.

Die Art, wie ich es derzeit mache, ist unten. Vielleicht sollte ich einfach glücklich damit sein. Aber ich schätze Leute haben das schon mal probiert.

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

Ich hatte damit zu tun, denke ich, vielleicht kann ich ausgraben, wie ich das angegangen bin. – kamranicus

+0

In Ordnung, ich musste nie benutzerdefinierte Validierungsbindungen erstellen, wir verwendeten die Attribute von MVC, um die Validierungsattribute auszugeben, und verwendeten auch die Hilfsmethode 'parseDynamicContent' bei AJAX-Aufrufen. Schau durch jquery.unobtrusive.js und ich bin sicher, es gibt eine Methode, die Sie aufrufen können, um die Regeln dynamisch hinzuzufügen. – kamranicus

Antwort

3

Interessante Frage! Hier ist eine reine KnockoutJS + VanillaJS Lösung. Es kann einige Falten geben, Cross-Browser-Zeug (ich schaue dich an, IE!), Und Ecken und Kanten. Lassen Sie mich in Kommentaren wissen oder schlagen Sie ein Update auf die Antwort vor, wenn Sie möchten.


Ansichtsmodell & Validierungsregeln:
Die Validierungsregeln sollten wie Attribute in .NET auf das Ansichtsmodell Eigenschaften, sehr nahe sein. Die Dokumentation für KnockoutJS schlägt vor, zu diesem Zweck extenders zu verwenden. Verbrauch würde wie folgt aussehen:

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!" } }); 

-Code für den Extender:
Der Extender aus der Dokumentation ist schön und einfach. Hier ist eine Alternative, die mehrere Validierungsfehler behandelt (obwohl es einige Arbeit für mehrere Regeln mit der gleichen Botschaft muss):

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

Vorlage für Validierungsmeldungen:
Um die Ansicht DRY zu machen und Validierung unaufdringlich würde ich definieren diese eine Vorlage für Validierungsfehler wie:

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

Ausblick:
Die aktuelle Ansicht kann sehr einfach sein:

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

Unauffällig und DRY, weil es keine Markup-Nachrichten hier mit Validierung ist. (Wenn Sie spezielle Markup für die Validierung wollen aber Sie könnten nur verwenden ein value Bindung und erstellen separaten Markup für name.errors.)

Benutzerdefinierte Bindung:
Und die custom binding würde nur tun, um:

  1. Injizieren Sie die Vorlage nach dem Eingabefeld.
  2. Wenden Sie die korrekte Vorlagenbindung mit dem als Daten beobachtbaren name an.
  3. Übergeben Sie den Rest an die Bindungen value und valueUpdate.

Hier ist die Bindung (das einige Refactoring benötigen, und jQuery/Javascript lovin' though):

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

Demo:
Um dies zu sehen alle in Aktion, haben einen Blick auf this jsfiddle.

Verwandte Themen