Jason
Jason

Reputation: 3030

Mapping observableArray to Multiple SELECT based off another json array

3I use jquery to $.getJSON and populate a SELECT dropdown with this information (the <OPTION>s value is the ItemID, and the text is the DisplayName):

//$.getJSON and populate <SELECT> options with this info
{"ItemOptions": [
 {"ItemID" : 1, "DisplayName": "Apples"},
 {"ItemID" : 2, "DisplayName": "Bananas"},
 {"ItemID" : 3, "DisplayName": "Oranges"},
 {"ItemID" : 4, "DisplayName": "Grapes"},
 {"ItemID" : 5, "DisplayName": "Carrots"},
 {"ItemID" : 6, "DisplayName": "Crushed Dreams"}
]}

Later on in the code, I get a shipment "manifest", which contains some information, of which includes a list of things that were shipped, it looks like this:

//manifest
{
    "LocationSource"    : "Dallas",
    "LocationDestination"   : "New York",
    "Items" : [
        {"ItemID" : 2},
        {"ItemID" : 3},
        {"ItemID" : 6}
    ],
    "Status" : "In Transit"
}
// then ko.mapping.toJS(manifest) and 
// ko.applyBindings(manifest) is done in javascript.

You'll notice that the Items array in the manifest have ItemID - which match up to the ItemID I've populated the SELECT with.

I use Knockout's mapping plugin -- and just ko.mapping.fromJS(manifest) -- works great. The INPUTs and SPANs and such where I map LocationSource, Status and the like are doing great.

My problem is that I want that SELECT to be a multiple, and representative of my Items in my manifest (the ability to add/remove them). HTML is like:

<input data-bind="value: LocationSource"/>
<input data-bind="value: LocationDestination"/>
<select multiple="multiple" data-bind="value: Items"></select>   // this thing

or

<select multiple="multiple" data-bind="value: Items().ItemID"></select>

doesn't seem to be cutting it for me, and I can't seem to figure out how to get it to work right (it appears that the ko.mapping is setting the Items to an array, but any time I make selections in the SELECT box, it explodes (either stays as it was when initialized, or gets changed from a function to a straight value, depending on how I tinker in code).

Essentially, my question is this:

I have a list of "things". They have IDs that match to an array in my manifest that is ko.mapped (and supposedly an .observableArray for that property). How can I add or remove from my Items based off that list of "things" (ItemOptions) -- so that when I push the ko.map.toJS(manifest) back up to the server, my Items array will still be a list of ItemIDs representative of what I chose in the SELECT.

edit: I've looked at adding the entire list as something like .AllItems to the manifest, like they show in the Knockout examples (self.AvailableMeals), but that's really not what I want -- nor do I want that entire list pushed back to the server when I map.toJS and $.post it back.

UPDATE

self.AllItems = ItemOptions;                                    //doesn't need to change, dont obvserable it, right?
self.Items = ko.observableArray(model.Items);   

Then, in the HTML I have:

<select data-bind="options: AllItems,  optionsText: 'DisplayName', selectedOptions: Items" size="15" multiple="true"></select>

This is getting me there, very close. It's manipulating the manifest like I expect it to -- the only issue now is that when I first load the manifest and apply bindings, the SELECT doesn't autoselect the Items that are in the manifest. I suspect this is because the Items array entry and the ItemOptions entry aren't identical? They both have ItemID, but one has DisplayName, and the other doesn't.

UPDATE 2

Added a jsfiddle: It will demonstrate that it works, but doesn't select the initial load:

http://jsfiddle.net/85Pvz/1

Upvotes: 0

Views: 696

Answers (1)

Major Byte
Major Byte

Reputation: 4101

If I understood your question correctly you want to use the selectedOptions binding?

so you'd have something like:

 <select data-bind="options: ItemOptions, selectedOptions: (manifest.)Items, optionsText: 'name', optionsValue: 'id'" size="5" multiple="true"></select> 

and for your javascript something like:

ItemOptions = [
    {name: "opt1", id: 1},
    {name: "opt2", id: 2},
    {name: "opt3", id: 3},
    {name: "opt4", id: 4} 
]

jsFiddle example

Upvotes: 1

Related Questions