Search code examples
javascriptknockout.js2-way-object-databinding

Knockout observableArray not updating all properties on checked value


I'm using Knockout to populate an observableArray based on the checked values of a separate observableArray. I can get the $data to copy over into the second set, but only one property comes through. I would like to have the entire object available. Is this a mapping issue, or something with the bindings?

HTML:

    <form role="form" data-bind="foreach: Colors">
      <input type="checkbox" data-bind="checkedValue: name, click: $root.ToggleAssociation, checked: $root.ColorChoice">
      <label data-bind="attr: {'for' : name}, text: id() + ' ' + name()"></label>
    </form>
    <div data-bind="foreach: ColorChoice">
      <span data-bind="text: $rawData.Id, style: { 'background-color': $rawData.Name }"></span>
    </div>

JavaScript:

    function Color(data) {
      var self = this;

      self.id = ko.observable(data.id);
      self.name = ko.observable(data.name);
      self.selected = ko.observable(false);
    }

    function viewModel() {

      var self = this;

      self.Colors = ko.observableArray([]);
      self.ColorChoice = ko.observableArray();

      self.Id = ko.observable();
      self.Color = ko.observable();

      self.init = function () {
        self.Colors.push(new Color({ id: 1, name: 'Red' }));
        self.Colors.push(new Color({ id: 2, name: 'Orange' }));
        self.Colors.push(new Color({ id: 3, name: 'Yellow' }));
        self.Colors.push(new Color({ id: 4, name: 'Green' }));
        self.Colors.push(new Color({ id: 5, name: 'Blue' }));
        self.Colors.push(new Color({ id: 6, name: 'Purple' }));
      }

      self.ToggleAssociation = function (item) {
        if (item.selected() === true)
          console.log("dissociate item " + item.id());
        else
          console.log("associate item " + item.id() + " " + item.name());
        self.Id(item.id());
        self.Color(item.name());
        item.selected(!(item.selected()));
        return true;
      };
    };

    var vm = new viewModel();
    ko.applyBindings(vm);
    vm.init();

https://jsfiddle.net/Razzle/ff1945ye/


Solution

  • You have an access to all of your variables in your model. If I am understanding exactly what you are trying to do and you would like to bind the click event whenever the checkbox is checked, you need to do something like this .

    Example :https://jsfiddle.net/kyr6w2x3/77/

    HTML:

    <form role="form" data-bind="foreach: Colors">
      <input type="checkbox" data-bind="checkedValue: name, click: $root.ToggleAssociation ,checked:selected">
      <label data-bind="attr: {'for' : name}, text: id() + ' ' + name()"></label>
    </form>
    <div data-bind="foreach: ColorChoice">
      <span data-bind="text: name, style: { 'background-color':name }" class="colors"></span>
    </div>
    

    JS:

     function Color(data) {
      var self = this;
    
      self.id = ko.observable(data.id);
      self.name = ko.observable(data.name);
      self.selected = ko.observable(false);
    }
    
    function viewModel() {
    
      var self = this;
    
      self.Colors = ko.observableArray([]);
      self.ColorChoice = ko.observableArray();
    
      self.Id = ko.observable();
      self.Color = ko.observable();
    
      self.init = function () {
        self.Colors.push(new Color({ id: 1, name: 'Red' }));
        self.Colors.push(new Color({ id: 2, name: 'Orange' }));
        self.Colors.push(new Color({ id: 3, name: 'Yellow' }));
        self.Colors.push(new Color({ id: 4, name: 'Green' }));
        self.Colors.push(new Color({ id: 5, name: 'Blue' }));
        self.Colors.push(new Color({ id: 6, name: 'Purple' }));
      }
    
      self.ToggleAssociation = function (item) {
       // here you can go through your array and do whatever you want to do
        item.selected(!item.selected());
         ko.utils.arrayFirst(self.Colors(), function (color) {
          if(color.id() == item.id()){
           if (item.selected()){self.ColorChoice.push(color);
           }else{self.ColorChoice.remove(color);
           }
          }
         });
        return true;
      };
    };
    
    var vm = new viewModel();
    ko.applyBindings(vm);
    vm.init();