Knockout Custom Validation with an observable parameter
Asked Answered
P

2

7

I have a situation where I need to validate the max amount of a field in my view model. However the max amount has to be variable and is calculated depending on a UI item selected outside of this model. I have attempted to include the observable as a parameter in my custom validator but it appears not to update when the value is changed.

I have a feeling that once the validation code is executed first time it holds on to the parameters.

The HTML of the list that's not using Knockout

<select id="ContentsReplacementAmount">
    <option value="25000">£25000</option>
    <option value="50000">£50000</option>
    <option value="75000">£75000</option>
</select>

Here is a dummed down version of the code I'm using.

var SpecifiedValuablesViewModel = function (maxSpecifiedItemAmount) {
    var self = this;

    self.maxSpecifiedItemAmount = ko.observable(maxSpecifiedItemAmount);

    self.amountToAdd = ko.observable().extend({
        validation: {
            validator: function (val, max) {
                return val <= max;
            },
            message: 'The amount must be a maximum of £{0}',
            params: self.maxSpecifiedItemAmount()
        }
    });
};

var specifiedValuablesViewModel = new SpecifiedValuablesViewModel($('#ContentsReplacementAmount').val());
ko.applyBindings(ko.validatedObservable(specifiedValuablesViewModel), document.getElementById('SpecifiedValuables'));

Event outside of the maxSpecifiedAmount

$('#ContentsReplacementAmount').on('change', function () {
    specifiedValuablesViewModel.maxSpecifiedItemAmount(parseInt($(this).val()));
});

My question is, how can I achieve this?

Phagy answered 4/12, 2013 at 16:41 Comment(2)
Usually I get a string representation of the number in $(asdf).val() and often the side-effect of === or <= tends to be invalid...ensure your 'max' and/or 'val' isn't a string.Chu
It's type is a string in this example but not in my app. It just won't change. Any other ideas? I'll update the code abovePhagy
P
6

I have now managed to figure this out using the following code:

Create a custom validator function

var customMax = function(val, max) {
    return val <= max();
};

Pass the validation function and wrap the message in a function

var SpecifiedValuablesViewModel  = function (maxSpecifiedItemAmount) {
    var self = this;

    self.maxSpecifiedItemAmount = ko.observable(maxSpecifiedItemAmount);

    self.amountToAdd = ko.observable().extend({
        validation: {
            validator: customMax,
            message: function () { return 'The maximum allowed is ' + self.maxSpecifiedItemAmount(); },
            params: self.maxSpecifiedItemAmount
        }
    });

    self.maxSpecifiedItemAmount.subscribe(function (amount) {
        self.amountToAdd.isModified(false);
    });
};

var specifiedValuablesViewModel = new SpecifiedValuablesViewModel($('#ContentsReplacementAmount').val());
ko.applyBindings(ko.validatedObservable(specifiedValuablesViewModel), document.getElementById('SpecifiedValuables'));

$('#ContentsReplacementAmount').on('change', function () {
    specifiedValuablesViewModel.maxSpecifiedItemAmount(parseInt($(this).val()));
});

JSFiddle example

Phagy answered 9/12, 2013 at 13:33 Comment(0)
S
2

This is a shot in the dark since I'm not all that familiar with the validation plugin, but try

    validation: {
        validator: function (val, max) {
            return val <= max();
        },
        message: 'The amount must be a maximum of £{0}',
        params: self.maxSpecifiedItemAmount
    }

This way you're passing the observable itself, rather than its value, as your validation parameter and evaluating it when the validator function is invoked rather than when the rule is defined.

Servant answered 5/12, 2013 at 18:33 Comment(1)
If I do this it some how clears the value of the self.maxSpecifiedItemAmount after it's changed, I think the validation clears itPhagy

© 2022 - 2024 — McMap. All rights reserved.