1

I'm new to KO and having trouble getting a computed value to work. I've got a viewmodel made up of many objects because I have many different tables in the database that I'm retrieving data from. This is an example of how I set the VM up. Feel free to critique anything I'm doing wrong in here (although it does work apart from the computed value):

var viewModel = function(object1, object2...) {
    var self = this;
    var activeProductCodes = ['AB-1', 'AB-2', 'AB-3'];

    self.myFirstObject = ko.observable({
        field1: ko.observable(object1.field1),
        field2: ko.observable(object1.field2),
        field3: ko.observable(object1.field3)
    });


    self.mySecondObject = ko.observable({
        productCode: ko.observable(object2.productCode),

        isActiveProduct: ko.computed(function() {
            return self.activeProductCodes.indexOf(productCode) !== -1 ? true : false;
        }, self)
    });
}

isActiveProduct doesn't work because it doesn't know what productCode is. I've tried doing this.productCode, self.productCode, self.mySecondObject().productCode, none of them seem to work. Is it possible to access the value? Is something wrong in my overall VM setup that is causing this to fail?

Thanks

Steve

UPDATE: I'm now not making the objects observable and declaring my VM as so:

var viewModel = function(object1, object2...) {
    var self = this;
    var activeProductCodes = ['AB-1', 'AB-2', 'AB-3'];

    self.myFirstObject = {
        field1: ko.observable(object1.field1),
        field2: ko.observable(object1.field2),
        field3: ko.observable(object1.field3)
    }

    self.mySecondObject = {
        productCode: ko.observable(object2.productCode),

        isActiveProduct: ko.computed(function() {
            return self.activeProductCodes.indexOf(productCode) !== -1 ? true : false;
        }, self)
    }
}
ministe
  • 543
  • 1
  • 5
  • 17
  • Why does `mySecondObject` exist at all? Why not just have both `productCode` and `isActiveProduct` on the `viewModel` itself? Another question - are you expecting `m6yFirstObject` and `mySecondObject` to change at all? If not they should be POJO's – Jamiec Jan 12 '17 at 08:59
  • Because the product belongs to the second object. There's many objects in the view model that I have to display on the page, I have a helpdesk ticket, the product they are having the problem with, details of any engineer visit etc etc which are all stored in separate tables in the database and I have to query for separately. In reality there's nearer 10 objects. I found when I was setting the VM up that if I didnt make the objects themselves observable that the page didnt receive updates – ministe Jan 12 '17 at 09:03
  • Unless you're changing the *whole* object for another object it does not need to be observable. If you just change *fields* of the object just make those fields observable. When you load an update from the server, update the fields themself not the whole object – Jamiec Jan 12 '17 at 09:04
  • Right, I'm not making the objects observable and have added updated code into my question, and this does still work. When I tried this before, the fields on the page didn't get updated but I must've just been doing something else wrong. However I still have my original problem, the computable doesn't get calculated correctly. How can I read the productCode field? When I break on this line of code, self doesn't contain mySecondObject which must be why I can't do self.productCode, so what should I be doing? PS I will later change my sub-VM declarations like your answer suggests – ministe Jan 12 '17 at 09:40
  • I'm afraid that you've now made this a straight duplicate. http://stackoverflow.com/questions/4616202/self-references-in-object-literal-declarations - my answer gives you a better option. – Jamiec Jan 12 '17 at 09:42
  • Also remember that inside `mySecondObject` `produceCode` is an observable so should be `self.mySecondObject.productCode()` to read it (note the parentheses) – Jamiec Jan 12 '17 at 09:46
  • Oh OK, so you're saying that by splitting out the sub-viewmodel that will actually be the fix so long as I use the function call? I thought you were just tidying up the code :) I'll do that now and feed back! – ministe Jan 12 '17 at 09:50
  • By using a proper sub view model it has its own scope which you can refer to using `self` just like your main view model – Jamiec Jan 12 '17 at 09:51

1 Answers1

1

The short discussion in comments aside, when I deal with sub-viewmodels in knockout I tend to define them properly, instead of using anonymous objects. So in your case that might look like this

var viewModel = function(object1, object2...) {
    var self = this;
    var activeProductCodes = ['AB-1', 'AB-2', 'AB-3'];

    self.myFirstObject = ko.observable(new myFirstViewModel(object1)); // omitted for brevity

    self.mySecondObject = ko.observable(new mySecondViewModel(object2, activeProductCodes ));
}

var mySecondViewModel = function(object2, activeProductCodes){
    var self = this;

    self.productCode = ko.observable(object2.productCode);
    self.isActiveProduct = ko.computed(function() {
            return activeProductCodes.indexOf(self.productCode()) !== -1 ? true : false;
    }, self)
}

I also mentioned that theres a good chance you dont need the sub viewmodels to actually be observable, so you might get away with this:

self.mySecondObject = new mySeocndViewModel(object2, activeProductCodes );

It depends on your use case.

Jamiec
  • 133,658
  • 13
  • 134
  • 193
  • Thanks, I'm updating the code as we speak, will report back! – ministe Jan 12 '17 at 09:22
  • should the colons inside mySecondViewModel not be equals signs? – ministe Jan 12 '17 at 09:51
  • woohoo it works! Thanks so much for all your help and quick responses, you're a life saver! I certainly wouldn't call myself a Javascript expert although I've used it a lot. The concept of "self" is new to me, and this is my first time using knockout so you've been a huge help! – ministe Jan 12 '17 at 10:17
  • @ministe2003 woohoo! glad I could help. I know KO pretty well, and have faced exactly this issue many times, so I knew how to fix it. – Jamiec Jan 12 '17 at 10:19