Eori
Eori

Reputation: 67

How to bind css class inside custom binding

I've created a custom binding to use as a color picker.

<ul data-bind="colorPicker: selcol"></ul>

It creates 10 inline divs each representing other color. When I click a div the color is selected. I have a problem with assigning the 'selected; css class to selected div. I try to use css binding inside custom binding but this doesn't work. It only selects initial div which stays selected even after selecting other div.

Please check the example: http://jsfiddle.net/zbkkzdsp/Jbvvq/

Thanks for any help. If you have any hints or comments to my code, please let me know. I'm quite new with knockout and will take any chance to learn more.

Upvotes: 1

Views: 1169

Answers (1)

Vlad Magdalin
Vlad Magdalin

Reputation: 1690

It seems like you're doing a lot of fancy stuff with computed values in your custom binding, so I would recommend creating view models for your colors.

First define a view model for each individual color:

var ColorModel = function(options) {
  var self = this;

  // Keep a reference to the parent picker for selection
  self.picker = options.picker;

  // The CSS value of the color
  self.color = ko.observable(options.color || 'transparent');

  // A flag denoting whether this color is selected
  self.selected = ko.observable(options.selected || false);

  // This will be called when the corresponding color link is clicked
  // Note that we're not doing any event binding with jQuery as with your custom binder
  self.select = function() {
    self.picker.selectColor(self); 
  };
};

Then a view model for the color picker itself:

var ColorPickerModel = function() {
  var self = this;

  // The list of all colors
  self.colors = ko.observableArray([]);

  self.addColor = function(color) {
    var newColor = new ColorModel({
        picker: self,
        color: color
    });

    self.colors.push(newColor);
    return newColor;
  };

  // Called by individual colors
  self.selectColor = function(colorModel) {
    // Deselect the current color so we don't select two
    var current = self.selected();
    if (current) {
      current.selected(false);
    }

    // Mark the color as selected - KO will do the rest
    colorModel.selected(true);

    // Remember this color as the selected one to deselect later
    self.selected(colorModel);
  };

  // Create at least one default color
  var transparent = self.addColor('transparent');

  // Keep track of the selected color - set to transparent by default
  self.selected = ko.observable(transparent);
  transparent.select();
};

Then bind your HTML view to your picker view model:

<div id="color-picker">
  <div data-bind="foreach: colors">
    <a href="#" data-bind="
       style: { 'background-color': $data.color }, 
       css: { 'selected': selected }, 
       click: select"></a>
  </div>
  <div>
    Selected color: <span data-bind="text: selected().color"></span>
  </div>    
</div>

And tie it all together:

var pickerDiv = document.getElementById('color-picker'),
    picker = new ColorPickerModel();

// Add some colors
picker.addColor('red');
picker.addColor('blue');
picker.addColor('green');
picker.addColor('orange');
picker.addColor('purple');
picker.addColor('black');

// Bind Knockout
ko.applyBindings(picker, pickerDiv);

// Add more colors - the view will update automatically
picker.addColor('pink');

Here's a working example: http://jsbin.com/izarik/1/edit

Upvotes: 3

Related Questions