0

I have a json structure like the following:

var scenario = {
    paints: [
       {
            product: 'Super Paint',
            sheens: [
                { sheen: 'Satin', cost: 42 },
                { sheen: 'Semi-Gloss', cost: 50 }
            ]
        },
        {
            product: 'Cashmere',
            sheens: [
                { sheen: 'Flat', cost: 42 },
                { sheen: 'Medium Lustre', cost: 50 }
            ]
        }
    ],
    walls: {
      "sheen":"Flat",
      "paintProduct":"Cashmere",
    },
    ceiling: {
      "sheen":"Flat",
      "paintProduct":"Cashmere",
   }
};

I figured out now to make drop-downs dependent for a given paintable item with the following:

function getSheens(paintProduct) {
    if (paintProduct) {
        for (var i = 0; i < self.scenario.paints.length; ++i) {
            if (self.scenario.paints[i].product === paintProduct) {
                return self.scenario.paints[i].sheens;
            }
        }
    }
    return null;
}

self.scenario.walls.sheens = ko.computed(function() {
    return getSheens(self.scenario.walls.paintProduct());
});

self.scenario.ceiling.sheens = ko.computed(function() {
    return getSheens(self.scenario.ceiling.paintProduct());
});

Here's the html:

<div class="item edit-walls" data-bind="with: scenario.walls">
    <label>Product</label>
    <select class="form-control paint-product" data-bind="options:$parent.scenario.paints, optionsText:'product', optionsValue:'product', value:paintProduct"></select>

    <label>Sheen</label>
    <select class="form-control paint-sheen" data-bind="options:$parent.scenario.walls.sheens, optionsText:'sheen', optionsValue:'sheen', value:sheen"></select>
</div>

The changing of the paint product for a given item, should reload the sheens of the newly select paint product.

The selected values for the paint product and sheen for the item, i.e. walls, are stored in the walls object.

What I would like to avoid is the repeating of the computed knockout call for each different item type. Is there a way to have this happen globally and pass in the context somehow?

I'm using knockout.js, knockout.viewmodel.js and jQuery.

Danno
  • 913
  • 3
  • 15
  • 28

1 Answers1

1

You're basically asking if it's possible to normalize "walls" and "ceiling" into one concept. You surely can. Let's call them paintables. Change your data structure to something like this:

var scenario = {
    paints: [/* omitted */],
    paintables: [
        { 
          "name":"walls",
          "sheen":"Flat",
          "paintProduct":"Cashmere"
        },
        { 
          "name":"ceiling",
          "sheen":"Flat",
          "paintProduct":"Cashmere"
    }]
};

You can then have a Paintable constructor function which implements the logic you have for sheens in a DRY manner.

Jeroen
  • 53,290
  • 30
  • 172
  • 279