EzDevInfo.com

Knockout-Validation

A validation library for Knockout JS

How to remove extender from an existing observable?

I am using the Knockout Validation plugin and setting an observable as required using the extender:

myObservable.extend({required:true});

Is it possible for me to remove the extender after adding it?


Source: (StackOverflow)

Knockout Validation async validators: Is this a bug or am I doing something wrong?

I really like how Eric Barnard's knockout validation lib integrates with observables, allows grouping, & offers custom validator pluggability (including on-the-fly validators). There are a couple of places where it could be more UX flexible/friendly, but overall it's reasonably well-documented... except, imo, when it comes to async validators.

I wrestled with this for a few hours today before doing a search and landing on this. I think I have the same issues/questions as the original author, but agree it wasn't clear exactly what duxa was asking for. I want to bring the question more attention so I am also asking here.

function MyViewModel() {
    var self = this;
    self.nestedModel1.prop1 = ko.observable().extend({
        required: { message: 'Model1 Prop1 is required.' },
        maxLength: {
            params: 140,
            message: '{0} characters max please.'
        }
    });
    self.nestedModel2.prop2 = ko.observable().extend({
        required: { message: 'Model2 Prop2 is required' },
        validation: {
            async: true,
            validator: function(val, opts, callback) {
                $.ajax({                                  // BREAKPOINT #1
                    url: '/validate-remote',
                    type: 'POST',
                    data: { ...some data... }
                })
                .success(function(response) {
                    if (response == true) callback(true); // BREAKPOINT #2
                    else callback(false);
                });
            },
            message: 'Sorry, server says no :('
        }
    });
}

ko.validation.group(self.nestedModel1);
ko.validation.group(self.nestedModel2);

A couple of notes about the code above: There are 2 separate validation groups, one for each nested model. Nested model #1 has no async validators, and nested model #2 has both a sync (required) and an async. The async invokes a server call to validate the inputs. When the server responds, the callback argument is used to tell ko.validation whether the user input is good or bad. If you put breakpoints on the lines indicated and trigger validation using a known invalid value, you end up with an infinite loop where the ajax success function causes the validator function to be called again. I cracked open the ko.validation source to see what was going on.

ko.validation.validateObservable = function(observable) {
    // set up variables & check for conditions (omitted for brevity)

    // loop over validators attached to the observable
    for (; i < len; i++) {
        if (rule['async'] || ctx['async']) {
            //run async validation
            validateAsync();
        } else {
            //run normal sync validation
            if (!validateSync(observable, rule, ctx)) {
                return false; //break out of the loop
            }
        }
    }

    //finally if we got this far, make the observable valid again!
    observable.error = null;
    observable.__valid__(true);
    return true;
}

This function is in a subscription chain attached to the user input observable so that when its value changes, the new value will be validated. The algorithm loops over each validator attached to the input and executes separate functions depending on whether or not the validator is async or not. If sync validation fails, the loop is broken and the whole validateObservable function exits. If all sync validators pass, the last 3 lines are executed, essentially telling ko.validation that this input is valid. The __valid__ function in the library looks like this:

//the true holder of whether the observable is valid or not
observable.__valid__ = ko.observable(true);

Two things to take away from this: __valid__ is an observable, and it is set to true after the validateAsync function exits. Now let's take a look at validateAsync:

function validateAsync(observable, rule, ctx) {
    observable.isValidating(true);

    var callBack = function (valObj) {
        var isValid = false,
            msg = '';

        if (!observable.__valid__()) {
            // omitted for brevity, __valid__ is true in this scneario
        }

        //we were handed back a complex object
        if (valObj['message']) {
            isValid = valObj.isValid;
            msg = valObj.message;
        } else {
            isValid = valObj;
        }

        if (!isValid) {
            //not valid, so format the error message...
            observable.error = ko.validation.formatMessage(...);
            observable.__valid__(isValid);
        }

        // tell it that we're done
        observable.isValidating(false);
    };

    //fire the validator and hand it the callback
    rule.validator(observable(), ctx.params || true, callBack);
}

It's important to note that only the first and last lines of this function are executed before ko.validation.validateObservable sets the __valid__ observable to true and exits. The callBack function is what gets passed as the 3rd parameter to the async validator function declared in MyViewModel. However before this happens, an isValidating observable's subscribers are invoked to notify that async validation has begun. When the server call is complete, the callback is invoked (in this case just passing either true or false).

Now here's why the breakpoints in MyViewModel are causing an infinite ping pong loop when server-side validation fails: In the callBack function above, notice how the __valid__ observable is set to false when validation fails. Here's what happens:

  1. The invalid user input changes the nestedModel2.prop2 observable.
  2. The ko.validation.validateObservable is notified via subscription of this change.
  3. The validateAsync function is invoked.
  4. The custom async validator is invoked, which submits an async $.ajax call to the server and exits.
  5. The ko.validation.validateObservable sets the __valid__ observable to true and exits.
  6. The server returns an invalid response, and callBack(false) is executed.
  7. The callBack function sets __valid__ to false.
  8. The ko.validation.validateObservable is notified of the change to the __valid__ observable (callBack changed it from true to false) This essentially repeats step 2 above.
  9. Steps 3, 4, and 5 above are repeated.
  10. Since the observable's value has not changed, the server returns another invalid response, triggering steps 6, 7, 8, & 9 above.
  11. We have ourselves a ping pong match.

So it seems like the problem is that the ko.validation.validateObservable subscription handler is listening to changes not just to the user input value, but also changes to its nested __valid__ observable. Is this a bug, or am I doing something wrong?

A secondary question

You can see from the ko.validation sources above that a user input value with an async validator is treated as valid while the server is validating it. Because of this, calling nestedModel2.isValid() cannot be relied on for "the truth". Instead, it looks like we have to use the isValidating hooks to create subscriptions to the async validators, and only make these decisions after they notify a value of false. Is this by design? Compared to the rest of the library this seems the most counter intuitive because non async validators don't have an isValidating to subscribe to, and can rely on .isValid() to tell the truth. Is this also by design, or am I doing something wrong here as well?


Source: (StackOverflow)

Advertisements

Clear error on Knockout-Validation

I have a page setup with Knockout.js and using Knockout-Validation.

During the page load I put another plugin on a select box which fires a change, which fires the validation. I need to be able to clear that error using JS so I can start with a fresh looking UI and give feedback on the form post or select box change.

I can't find anything that allows me to clear an error in Knockout-Validation.


Source: (StackOverflow)

Knockout Validation - How to show error messages

We're using Knockout.js and the Knockout-validation plugin. When a user returns to a page that has validation errors, we want the error messages to display. Does anyone know if it's possible to trigger knockout validation without actually changing the bound answer?


Source: (StackOverflow)

Knockout validation

I have asp.net mvc3 project where I do a bulk edit on a table with knockout binding. I want to do validations like required and number validations while saving data. Is there any easier way to do knock out validations. PS: I am not using forms.


Source: (StackOverflow)

Knockout Validation evaluates immediately on load

I'm using MVC, Knockout, and Knockout Validation to validate my view model.

I'm running into an issue where the validation for view model properties are firing immediately upon loading. In other words, "This field is required" shows up next to my inputs before a user has attempted to change their values.

This problem is specifically happening with dropdown (select) controls.

I'm guessing that this is a problem that I've created by somehow unintentionally changing/accessing/mutating the observable in another part of my javascript code. However, I don't know how to track this down.

Is there a way that I can somehow subscribe or track the even that fires that causes validation in Knockout Validation? I just need to know why this is firing in the way it is. I'm pretty confident that the value of the isValid() function is consistently false.

Here's a sample of how my HTML is setup on page load, unmolested:

<select class="highlightable validationElement" name="obsstate" data-bind="value: standardAnswers.ans106_1.value" required="true">
    <option value="">-- Select -- </option>
        <option value="AK">AK</option>
        <option value="AL">AL</option>
        etc...

</select>

As displayed on my local machine


Source: (StackOverflow)

Add CSS Class with Knockout Validator

I want to add a CSS Class to a select element in my view, my view model has a property which I've extended using Knockout-Validation:

self.selectedRootCause = ko.observable().extend({
    required: true
});

Then my select is like so:

<form data-bind="submit: closeComplaint" method="post"> 
    <select data-bind="options: rootCauses, 
                            optionsText: 'RootCauseText', 
                            value: selectedRootCause, 
                            optionsCaption: 'Choose..',
                            validationOptions: { errorElementClass: 
                                                 'input-validation-error' }">
    </select>

    <input type="submit" value="Close Complaint" />
</form>

My closeComplaint function looks like so:

self.closeComplaint = function () {
    if (self.errors().length == 0) {
        $.ajax({
            url: '@Url.Action("CloseComplaint")',
            data: new DetailsComplaintAdmin(self.currentComplaint(),
                                        self.selectedRootCause().RootCauseId
                ),
            success: function (data) {
                console.log(data);
            }
        });
    }
}

Just for completion, here is my self.errors() function:

self.errors = ko.validation.group(self);

The problem is the class input-validation-error doesn't appear to be added to my select input when I submit my form? Any ideas?


Source: (StackOverflow)

Set a custom error message using the native rules of the knockout validation plugin

I am using Asp.net MVC3 and knockoutjs library. I need to do some client side validation. I am exploring the knockout validation plugin.

So I declare the following ko.observable value in my js code:

 var numberValue = ko.observable().extend({ number: true }) 

This is my view part:

<input data-bind = "value: numberValue " />

When the user enters some value that is not a number an error message is displayed : "Please enter a number". Can I display a different error message but still using the native rules? I do not want to write custom validation logic just for this. Any help with some working example will be greatly appreciated. Thank You!


Source: (StackOverflow)

Knockout Mapping Validation

I'm trying to attach validation to a mapped view. I'm using Knockout Mapping and Validation plugins. Pseudo-models:

Person {
    int Id;
    string Name;
    Book[] Books;
}

Book {
    int Id;
    string Name;
}

Javascript:

function viewModel() {
    var self = this;
    self.persons = ko.observableArray();

    // persons are retrieved via AJAX...
    ko.mapping.fromJS(persons, {}, self.persons);
}

jQuery(function( $ ) {
    ko.applyBindings(new viewModel());
});

How can I extend persons observableArray to set validation rules and message? I need to validate both persons and books sub-array properties. I've found only examples that use explicit model setting, without automatic mapping, something like:

Name: ko.observable().extend({ required: true })

Then I'll need to set ko.validatedObservable, isValid and validation.init, but I really don't know how to handle/organize this. Can you please provide some help?


Source: (StackOverflow)

Knockout Validation ko.validation.group vs ko.validatedObservable

What is the difference in ko.validation.group and ko.validatedObservable? Are there particular situations when I should use one over the other?


Source: (StackOverflow)

KnockoutValidation and the conditional required rule

I am trying to use KnockoutValidation with conditional statements. See code below:

self.transactionType = ko.observable('Option1');

self.ConditionalField = ko.observable().extend({
  required: true, 
  onlyIf: self.transactionType = ="Option2"
});

Unfortunately this doesn't work. I want to have ConditionalField only required if transactionType has value 'Option2'.

What is the best way to use conditional validation with knockout.validation.js?


Source: (StackOverflow)

Knockout validation: Dynamic constraints

I'm using Durandal, which in turn leverages off of Knockout.

I want to be able to Change validation lengths dynamically

enter image description here

Fiddle

The fiddle seems to be behaving slightly different than my "working" solution, but its still not doing what I'm wanting/expecting it to.

Viewmodel JS:

[Attempt 1]

define(function () {

   var self = this;

   self.userInfo = {       
        IdOrPassportNumber: ko.observable().extend({
            required: true,
            pattern: {
                message: 'A message',
                params: /some regex/
            }
        }),
        IdType: ko.observable()
    },

    self.isIdValid = ko.validatedObservable({ 
         IdOrPassportNumber: self.userInfo.IdOrPassportNumber 
    });

    self.userInfo.IdOrPassportNumber.subscribe(function (value) {
          if (isIdValid.isValid()) {
               console.log('YOLO!');
          }
    });

    self.userInfo.IdType.subscribe(function (value) {
        console.log(value);
        if (value === 'Passport') {
            self.userInfo.IdOrPassportNumber.extend({ maxLength: 15 });
        } else {
            self.userInfo.IdOrPassportNumber.extend({ maxLength: 13 });
        }
    });    

    var viewModel = {
        userInfo: self.userInfo
    };

    viewModel["errors"] = ko.validation.group(viewModel.userInfo);
    viewModel["errors"].showAllMessages();

    return viewModel;
});

What seems to be happening is that when i start typing i get the max & min validation of 13, but if i continue typing the validation changes to 15. I have tried another route of, setting the min & max length in the initial observable extend EG, just after the regex, and then setting the min and max length to use an observable, to no success.

[Attempt 2]

   self.userInfo = {       
       IdOrPassportNumber: ko.observable().extend({               
            maxLength: self.maxLength(), 
            minlength: self.maxLength()
       }),
       IdType: ko.observable()
   },

   self.maxLength = ko.observable();

   self.userInfo.IdType.subscribe(function (value) {

          if (value === 'Passport') {
             self.maxLength(15)
          } else {
              self.maxLength(3)
          }
    });

Source: (StackOverflow)

knockout Validation: Any option to apply the errorElementClass to parent of input?

Does the Knockout validation plugin have any option to apply the error class to the parent or parent's-parent of the input in error? If not can anybody suggest an approach to modify knockout validation to do this?

Please see the following fiddle for an example of what I'm trying to achieve. Out of the box knockout validation sets the class of the input, but I want it to instead set the class of the containing control-group:

http://jsfiddle.net/fbA4m/1/

View

<p>Clear the field and tab out of it to "see" the current behaviour - error class is added directly to the input by knockout validation. But I want to add class "error" to control-group containing the input instead of directly to the input.</p>
<div class="form-horizontal">
<div class="control-group">
<label class="control-label">Field</label>
<div class="controls">
<input type="text" data-bind="value: testField" class="">
</div>
</div>
    <button data-bind="click: setErrorOnControlGroup">Click to see desired effect</button>
</div>

Javascript

ko.validation.configure({
    registerExtenders: true,
    messagesOnModified: true,
    decorateElement: true,
    errorClass: 'error',
    insertMessages: false,
    parseInputAttributes: true,
    messageTemplate: null
});

var viewModel = {
    testField: ko.observable("123").extend({required: true}),
    setErrorOnControlGroup: function() {
        $("input.error").removeClass("error");
        $(".control-group").addClass("error");
    }
};

ko.applyBindings(viewModel);

Stylesheet (Illustrative only - I shouldn't need this because I want to the use the twitter bootstrap styles)

/*NOTE: This is not actually the style I want, it just illustrates the default behaviour of knockout validation*/
input.error {
    background-color: #aaffaa;
}

I ask because I'm using twitter bootstrap styling and it uses the input's parent control-group element to style "error" inputs.


Source: (StackOverflow)

Knockout Validation and Qtip

I currently use Jquery Validation and Qtip together to deal with the actual validation and displaying of information to the screen using the nice tooltip style notifications upon validation errors using the errorPlacement component of the validation options.

Currently each viewModel has its own custom method for setting up and kicking off the validation and callbacks, however I was trying to look at a nicer way of doing this, be it adding a custom binding to setup my validation rules via the data-bindings or an alternative way, but still yielding the same results (i.e the errorPlacement is triggered when a validation error occurs and tells Qtip to display the error for the given element).

Now before I started making one myself I just checked online and found Knockout Validation, which I initially thought was a great idea, I could apply my validation logic directly to the data within my viewModel and then just find some sort of callback to get Qtip to kick in, however it seems there is no callback that I can find documented. The library seems to do everything I want for the validation side of things, just not for the displaying side of things. I looked through the source code and examples but couldn't see anything other than ko.validation.group(viewModel) which would give me an observable containing the errors, but I am not sure if I could use this the same way as I was expecting.

Here is an example of how my current validation happens:

/*globals $ ko */
function SomeViewModel() {

    this.SetupValidation = function () {
        var formValidationOptions = {
            submitHandler: self.DoSomethingWhenValid,
            success: $.noop,
            errorPlacement: function (error, element) {
                if (!error.is(':empty'))
                { qtip.DoSomethingToDisplayValidationErrorForElement(element, error); }
                else
                { qtip.DoSomethingToHideValidationErrorForElement(element); }
            }
        };

        $(someForm).validate(formValidationOptions);
        this.SetupValidationRules();
    };

    this.SetupValidationRules = function() {
        $(someFormElement1).rules("add", { required: true, minlength: 6, maxlength: 20, alphaNumeric: true });
        $(someFormElement2).rules("add", { required: true, minlength: 6, maxlength: 20 });
        $(someFormElement3).rules("add", { required: true, email: true, });
    };
}

I currently am sure I can remove the need for the validation rules method by adding a custom binding so I can set the validation in the data-bind, however if possible I would like to use the same sort of callback approach with the existing Knockout-Validation binding.


Source: (StackOverflow)

Validate on Blur

I've created a JSFiddle to help demonstrate my question: http://jsfiddle.net/jeffreyrswenson/CrYWn/5/

Here's what I'd like to see:

  • Messages should not appear when page loads.
  • Messages should appear when submit button is pushed.
  • Messages should appear after input value is changed and user leaves element. (Tabs or clicks to next field)
  • Messages should appear after user leave an input without changing.(For example a field is required and the user tabs through the field, but doesn't enter a value. I'd like the validation message to appear when this happens.)

The first four work as I'd expect. Is the last item possible and if so, what do I need to change to enable that behavior?

HTML:

<label>First name:
<input data-bind='value: firstName' />
</label>
<br/>
<label>Last name:
    <input data-bind='value: lastName' />
</label>
<br/>
<button type="button" data-bind='click: submit'>Submit</button>
<br/>
<span data-bind='text: errors().length'></span> errors

ViewModel:

var viewModel = function () {
       ko.validation.configure({
           decorateElement: true,
           registerExtenders: true,
           messagesOnModified: true,
           insertMessages: true,
           parseInputAttributes: true,
           messageTemplate: null
       });

       this.firstName = ko.observable().extend({
           required: true
       });
       this.lastName = ko.observable().extend({
           required: true,
           pattern: {
               message: 'Hey this doesnt match my pattern',
               params: '^[A-Z0-9]+$'
           }
       });

       this.submit = function () {
           if (this.errors().length == 0) {
               alert('Thank you.');
           } else {
               this.errors.showAllMessages();
           }
       };
       this.errors = ko.validation.group(this);
   };

Source: (StackOverflow)