Search code examples
javascriptknockout.jsknockout-validation

Knockout computer function cannot be evaluated


Please check my plunkr here:

https://plnkr.co/edit/pwKohFTmLPW1BKNwHxWR?p=preview

I have a simple computer function:

self.SubscribersOrEmails = ko.computed(function() {
    var counter = 0;
    if (self.Emails != null && self.Subscribers != null) {
        counter = self.Emails().length + self.Subscribers().length;
    }
    console.log("counter: " + counter);
    return counter;
}, self);

When I get to use it like this: self.SubscribersOrEmails() then I get the error that 'SubscribersOrEmails is not a function' but when I do console.log(self.SubscribersOrEmails) then it prints out a function. So it IS a function. How do I use it then? I want it to return an integer. Currently it returns a function, but I am not allowed to evaluate it.

Any idea what is going on with it?

UPDATE

Some people have been seeing an old version of the plunkr for some bizarre reason.

I can now see that it's a declaration order issue. If I do this:

self.SubscribersOrEmails = ko.computed(function() {
              var counter = 0;
                if (self.Emails != null && self.Subscribers != null) {
                    counter = self.Emails().length + self.Subscribers().length;
                }
            console.log("counter: " + counter);
            return counter;
        }, self); 

 self.Subscribers = ko.observableArray().extend({ required: { onlyIf: function () { console.log(self.SubscribersOrEmails()); return self.SubscribersOrEmails === 0}, params: 'Subscribers', message: "Please either select a user or type email address(es)" } })
 self.Emails = ko.observableArray().extend({ required: { onlyIf: function () { return self.SubscribersOrEmails == 0 }, params: 'Emails' } })

Then the function works but Emails and Subscribers is always zero because they don't exist when they are read.

If I do the opposite then the function doesn't exist.

So all possible order declarations cause problems :(


Solution

  • This is because your order of declaration. In the extend method, you are referring to a method that hasn't been declared yet. You can fix this by extending those observables after declaring that computed property.

    self.Subscribers = ko.observableArray();
    self.Emails = ko.observableArray();
    self.SubscribersOrEmails = ko.computed(function() {
        var counter = 0;
        if (self.Emails != null && self.Subscribers != null) {
            counter = self.Emails().length + self.Subscribers().length;
        }
        console.log("counter: " + counter);
        return counter;
    }, self); 
    
    self.Subscribers.extend({ required: { onlyIf: function () { return self.SubscribersOrEmails == 0 }, params: 'Subscribers', message: "Please either select a user or type email address(es)" } })
    self.Emails.extend({ required: { onlyIf: function () { return self.SubscribersOrEmails == 0 }, params: 'Emails' } })