0

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

1 Answer 1

1

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

Sign up to request clarification or add additional context in comments.

7 Comments

This is the right path. I'm getting there, except my Items in my manifest only have a numeric array, without the ItemID label - when I start clicking around. It also doesn't have them preselected. I suspect it's because what's in Items and what's in ItemOptions are identically flavored arrays?
If you leave out the optionsValue parameter you get the entire object, see here
I was able to do that - and that works great, it gives me the labels like I wish. Now my only problem is when I am initially loading the manifest (applying the bindings), the SELECT isn't :selected'ing the choices that are in the manifest (probably because they're not similar arrays, one just has ItemID the other has ItemID and DisplayName). In short, in my example above -- items 2,3,6 are not selected in the SELECT. Any ideas?
I've updated my original post up top to reflect where it is at now, working but not selecting the items initially when loading and applying bindings. If I click in the SELECT, it populates the Items right, but on that initial load, it's not selecting what it already has.
The thing is, in javascript, object {"ItemId":1, "DisplayName": "Apples"} != object {"ItemID":1, "DisplayName": "Apples"}. That's why you want to specifiy the optionsValue parameter, because then you've given knockoutjs a "key" to compare on for equality. That way you can set self.SelectedItems([1,2,3]) and it will select those in the multi-select. But if you really need to have your id as objects, you could add a subscriptions to SelectedItems, and have that one update the Items object, like so
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.