Knockout Custom Validation with an observable parameter

12.7k Views Asked by At

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?

2

There are 2 best solutions below

0
On BEST ANSWER

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

1
On

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.