Knockout Custom Validation with an observable parameter

Stokedout picture Stokedout · Dec 4, 2013 · Viewed 10.3k times · Source

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?

Answer

Stokedout picture Stokedout · Dec 9, 2013

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