2013-03-07 40 views
11

Sử dụng MVC 4 với KnockoutJS. Tôi có thể ràng buộc xác nhận không phô trương với một ràng buộc loại trực tiếp tùy chỉnh? Tôi hiện đang rebinding việc xác nhận bằng cách sử dụng một mẫu với afterRender. Tôi rất thích có nó tự động thêm vào với các ràng buộc. Như thế này:Ràng buộc xác thực không phô trương với ràng buộc KnockoutJS tùy chỉnh

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

Tôi đã bận rộn với nó cả ngày. Tôi không thể làm điều đó mà không vô cùng hiệu quả.

Cách tôi hiện làm, bên dưới. Có lẽ tôi chỉ nên hạnh phúc với nó. Nhưng tôi đoán mọi người đã thử điều này trước đây.

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

Tôi đã phải đối phó với điều này tôi nghĩ, có lẽ tôi có thể đào lên cách tôi tiếp cận điều này. – kamranicus

+0

Được rồi, tôi không bao giờ phải tạo bất kỳ ràng buộc xác thực tùy chỉnh nào, chúng tôi đã sử dụng các thuộc tính của MVC để xuất các thuộc tính xác thực và cũng sử dụng phương thức trợ giúp 'parseDynamicContent' khi thực hiện các cuộc gọi AJAX. Xem qua jquery.unobtrusive.js và tôi chắc chắn có một phương pháp bạn có thể gọi để thêm các quy tắc động. – kamranicus

Trả lời

3

Câu hỏi thú vị! Dưới đây là một giải pháp tinh khiết KnockoutJS + VanillaJS . Có thể có một số nếp nhăn, các công cụ trình duyệt chéo (Tôi đang xem bạn, IE!) Và các cạnh thô. Hãy cho tôi biết trong nhận xét hoặc đề xuất cập nhật câu trả lời nếu bạn muốn.


Rules ViewModel & Validation:
Các quy tắc xác nhận nên được gần gũi với thuộc tính của ViewModel, giống như các thuộc tính trong .NET. Tài liệu cho KnockoutJS đề xuất sử dụng extenders cho mục đích này. Cách sử dụng sẽ trông như thế này:

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

Mã cho Extender:
Các extender từ tài liệu là tốt đẹp và đơn giản. Dưới đây là một sự thay thế để xử lý nhiều lỗi xác nhận (mặc dù nó cần một số công việc cho nhiều quy tắc với cùng một thông điệp):

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

Template cho các tin nhắn xác nhận:
Để thực hiện Xem DRY và xác nhận không phô trương Tôi muốn xác định một khuôn mẫu để xác nhận lỗi như thế này:

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

Xem:
Quan điểm thực tế có thể rất đơn giản:

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

Không phô trương và DRY, vì không có đánh dấu đây với những thông điệp xác nhận. (Nếu bạn muốn đánh dấu đặc biệt đối với xác nhận của bạn, mặc dù bạn thể chỉ cần sử dụng một value ràng buộc và tạo đánh dấu riêng biệt cho name.errors.)

Tuỳ chỉnh ràng buộc:
custom binding sẽ chỉ làm, theo thứ tự:

  1. Tiêm mẫu sau trường nhập.
  2. Áp dụng đúng mẫu ràng buộc với name có thể quan sát dưới dạng dữ liệu.
  3. Chuyển phần còn lại vào các liên kết valuevalueUpdate.

Dưới đây là các ràng buộc (có thể cần một số refactoring, và jQuery/lovin javascript mặc dù):

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:
Để xem tất cả điều này trong hành động, có một peek tại this jsfiddle.

Các vấn đề liên quan