Search code examples
javascriptknockout.jsknockout-validation

How do I call an observable property within its own validation extender?


I'm attempting to create a drop-down list of countries using the knockout framework in ASP MVC4. The validation requirement is fairly simple - a country has to be selected before the control is validated. The relevant code in the view model is as follows:

function viewModel(model) {
    var _self = this;

    // Various guff
    _self.ConfirmationOption = ko.observable(model.ConfirmationOption).extend({ required: { message: _self.mdata.requiredMessage } }); //mdata is part of the guff

    _self.CountryOfPractice = ko.observable(model.CountryOfPractice).extend({
        required: {
            message: "You must select a country",
            onlyIf: function () { return (_self.ConfirmationOption() === '4' && (_self.CountryOfPractice() === null || _self.CountryOfPractice() === undefined)); }
        }
    });

    // Assorted other guff
}

When I try to run this, Firebug tells me that an error occurs trying to parse, showing:

TypeError: _self.CountryOfPractice() is not a function.

My limited understanding of knockout is that properties declared as ko.observable are not strictly JS properties and have to be accessed as functions in order to obtain their current value. In most other areas of code this normally works fine. The reason I attempt this access to the value within the validator extension is to ensure that a selection has been made.

I can see in the debugger that CountryOfPractice is not yet part of _self, so I can somewhat see how the error occurs. I tried factoring out the test into another function declared beforehand but that function then fails because it hasn't yet seen CountryOfPractice(), if I place it after this method it fails because CountryOfPractice()'s extender hasn't yet seen my validation method...

What pattern do I need to use in order to be able to get the function to work?


Solution

  • The solution was to call the extend function on a new line - can anyone explain why?

    _self.CountryOfPractice = ko.observable(model.CountryOfPractice);
    
    _self.CountryOfPractice.extend({
        required: {
            message: "You must select a country",
            onlyIf: function () { return (_self.ConfirmationOption() === '4' && (_self.CountryOfPractice() === null || _self.CountryOfPractice() === undefined)); }
        }