3

I am trying get a list of checkboxes get checked based on two observablearrays. The first one has a few programids and the second one will have all the records of programids. Both the observablearray's data come from the database.

Basically I am trying to get the list of programid already assigned for a user which is in ProgramIDs array and compare it with the array of AllPartnerPrograms array and show the ones that match as checked.

Then I want to be able to check from the new list and send it back to the server to update the user's data with the new list of programid.

I am not sure why the checkedValue binding is not work or I do not understand how to make it work. I created a fiddle with the same code here.

I am assuming that $root.AllPartnerPrograms will get show the checked items based on the self.ProgramIDs array but that does not happen.

If I put the code like this, it gets checked but does not show me the other records.

 <input type="checkbox" data-bind="checkedValue: ProgramID, checked: ProgramID" />  

If I change the foreach to <!-- ko foreach: AllPartnerPrograms --> then I get the other records but still not check based on the first list.

What am I doing wrong here?

My code

<div id="programs">
<!-- ko foreach: ProgramIDs -->    
<input type="checkbox" data-bind="checkedValue: ProgramID, checked: $root.AllPartnerPrograms" />    
<span data-bind="text: ProgramName"></span>
<!-- /ko -->

View Model

var objPartnerPrograms;
vmPartnerProgramsModel = function () {
var self = this;

self.ProgramIDs = ko.observableArray(
[{ProgramID: 16002,ProgramName: "Program1"}, 
 {ProgramID: 16003,ProgramName: "Program2"}, 
 {ProgramID: 16005,ProgramName: "Program3"}, 
 {ProgramID: 16006,ProgramName: "Program4"}, 
 {ProgramID: 16011,ProgramName: "Program5"
}]);

self.AllPartnerPrograms = ko.observableArray(
[{ProgramID: 16002,ProgramName: "Program1"}, 
 {ProgramID: 16003,ProgramName: "Program2"}, 
 {ProgramID: 16005,ProgramName: "Program3"}, 
 {ProgramID: 16006,ProgramName: "Program4"}, 
 {ProgramID: 16011,ProgramName: "Program5"}, 
 {ProgramID: 16102,ProgramName: "Program6"}, 
 {ProgramID: 16104,ProgramName: "Program7"
 }]);
};

$(document).ready(function () {
  objPartnerPrograms = new vmPartnerProgramsModel()
  ko.applyBindings(objPartnerPrograms, $("#programs")[0]);
});
Adrian
  • 333
  • 6
  • 20
  • Your sentence starts with *"My objective here is"* and then it starts to get very unclear. Can you rephrase that, please? – Tomalak Dec 07 '14 at 09:26
  • repharased hope it is clearer now – Adrian Dec 07 '14 at 09:32
  • Not really, I'm afraid. But I sense you are trying to do the wrong thing. Do you *really* have two lists, or do you really have *one* list, of which some items are checked ("assigned", whatever you call it) and others are not? I think you are trying to build a confusing user interface for something that isn't a very hard problem in the first place. Maybe it's better to describe what data you want to represent, instead of what UI you want to build for it. – Tomalak Dec 07 '14 at 09:38
  • Let me try to explain and not confuse myself and you together. From a main list I have assigned a few programids to user like 16002 to 16011 and it is save to the database. So when I edit the user I will have the list of programids. Now I want these programids to get checked against the main list – Adrian Dec 07 '14 at 09:45
  • 1
    So you have *one single* list of which some items are checked and others are not (a different set for each user, obviously, but nevertheless). Something like this, maybe? http://jsfiddle.net/ekb85ftg/8/ – Tomalak Dec 07 '14 at 09:56
  • BTW, check out http://stackoverflow.com/questions/9233176/unique-ids-in-knockout-js-templates for a way to use ``+` – Tomalak Dec 07 '14 at 09:59
  • Your fiddle works as I need let me try and see how this works – Adrian Dec 07 '14 at 10:02

2 Answers2

2

Your not scoping your observable properly within your foreach loop, it should be accessed via $data.

Saying that, I'd only keep a single observable list with all options. Extend this option to have a boolean that the checked field can work with properly. When you come to save the values back to the database you can just loop through your array and get the ones that are checked.

var self = this;
var Program = function(id, name, isChecked) {
    return {
        id: ko.observable(id),
        name: ko.observable(name),
        isChecked: ko.observable(isChecked)
    }
}

self.programArray = ko.observableArray([]);
// populate observable array checking the programs that match in both your lists
self.programArray.push(new Program(1234, 'name', true));

// in page
<!-- ko foreach: programArray -->
    <input type="checkbox" data-bind="checked: $data.isChecked" />
<!-- /ko -->

HTH

Peter Lea
  • 1,731
  • 2
  • 15
  • 24
  • This answer works perfect also if you manage the display and edit options int he scripts: `` – Juan Acosta Sep 08 '16 at 09:30
1

Your view model ProgramIDs property should only contain IDs of selected items, not full elements:

self.ProgramIDs = ko.observableArray([16002, 16003, 16005, 16006, 16011]);

You also need to bind to full list property in foreach binding and use ProgramIds for checked binding:

<div id="programs">
    <!-- ko foreach: AllPartnerPrograms -->    
    <input type="checkbox" data-bind="checkedValue: ProgramID, checked: $root.ProgramIDs" />
    <span data-bind="text: ProgramName"></span>
    <!-- /ko -->
</div>

See updated jsFiddle.

dotnetom
  • 24,551
  • 9
  • 51
  • 54