Stephen McCormick
Stephen McCormick

Reputation: 1796

Knockout Javascript Select Mapping

Looked at a lot of stackoverflow examples but to no avail. I have a javascript array of strings which I wish to map to a ko observableArray, which I then want to apply to a select in my HTML. Here is the main ko object:

actionData: {
    json: false,
    xml: false,
    pdf: false,
    word: false,
    csv: false,
    excel: false,
    prophet: false,
    editablePdf: false,
    editableWord: false,
    zip: false,
    httpUrl: null,
    username: null,
    password: null,
    connectionTest: false,
    requiredAlerts: [],
    folder: null,
    first: null,
    libraries: []
},

Then when my ajax call returns with the data I map it. At this point I have verified that it is happy (see the "first" variable has have the proper data when I look at it the debugger):

var list = JSON.parse(data.libraries);
self.CurrentAction.actionData.libraries = ko.observableArray(list);
//self.CurrentAction.actionData.folder = ko.observable();
self.CurrentAction.actionData.first = ko.observable(list[0]);
var first = self.CurrentAction.actionData.libraries()[0];

Finally in my .CSHTML I do the following:

<div class="row">
    <div class="col-xs-12 col-sm-10 col-sm-offset-2" data-bind="with: CurrentAction.actionData">
        <div class="checkbox"><label><input class="format-checkbox" type="checkbox" data-bind="checked: editablePdf"> Make PDF document editable</label></div>
        <div class="checkbox"><label><input class="format-checkbox" type="checkbox" data-bind="checked: editableWord"> Make Word document editable</label></div>
    </div>
</div>
<div class="row">
    <div class="col-xs-12 col-sm-6" data-bind="with: CurrentAction.actionData">
        <label>LIB</label>
        <input data-bind="value: first">
    </div>
</div>
<div class="col-xs-12" style="padding-left:0px; padding-right:0px">
    <label>SharePoint Library</label>
    <!-- ko with: CurrentAction.actionData. -->
    <select data-bind="options : libraries,
                        value : folder,
                        optionsCaption : 'Please choose a SharePoint Library...'"
            style="width: 100%; padding-top: 5px; padding-bottom: 5px; padding-left: 5px; border-radius:4px;border:1px solid #AAAAAA;">
    </select>
    <!-- /ko -->
    <p style="font-size: 13px; margin-top: 5px;">Your files will be sent to this library when submitted</p>
</div>

And I get nothing in the select. I have verifies that other elements in the construct are there, but for some reason the "libraries" is not or I am mapping it incorrectly?

enter image description here

UPDATE

Thanks to the great answers below I have figured it all out. Basically I had a few problems:

  1. My actionData was actually mapping to another object which was missing the library object. This was due to some other code that I was unaware of. Once I got that fixed the data started to map/bind correctly

  2. Once I had the correct object the library was already an observeableArray, so there was no need to re-map it to observable. The new code looks like:

if (data.statusCode == "200") { var list = JSON.parse(data.libraries); self.CurrentAction.actionData.libraries(list); }

  1. Finally, the previous incorrect object had been persisted, so when I ran again the old object persisted (incorrect) data was being loaded and ruining everything.

The final HTML version looks like this:

       <div class="col-xs-12" style="padding-left:0px; padding-right:0px">
            <label>SharePoint Library</label>
            <select data-bind="options : CurrentAction.actionData.libraries,
                               value : CurrentAction.actionData.folder,
                               optionsCaption : 'Please choose a SharePoint Library...'"
                    style="width: 100%; padding-top: 5px; padding-bottom: 5px; padding-left: 5px; border-radius:4px;border:1px solid #AAAAAA;">
                <option data-bind="text: Name"></option>
            </select>
            <p style="font-size: 13px; margin-top: 5px;">Your files will be sent to this library when submitted</p>
        </div>

Many thanks for the great answers!

Upvotes: 1

Views: 57

Answers (1)

Bryan Dellinger
Bryan Dellinger

Reputation: 5294

I'm not quite following your question but I used your data and mapped it to a select using the options binding it seemed to work ok. run snippet below

var data = {
  json: false,
  xml: false,
  pdf: false,
  word: false,
  csv: false,
  excel: false,
  prophet: false,
  editablePdf: false,
  editableWord: false,
  zip: false,
  httpUrl: null,
  username: null,
  password: null,
  connectionTest: false,
  requiredAlerts: [],
  folder: 'three',
  first: null,
  libraries: ['one', 'two', 'three', 'four', 'five']
}
var viewModel = ko.mapping.fromJS(data);

$(document).ready(function() {
  ko.applyBindings(viewModel);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>

<select data-bind="options : libraries,
                        value : folder,
                        optionsCaption : 'Please choose a SharePoint Library...'" style="width: 100%; padding-top: 5px; padding-bottom: 5px; padding-left: 5px; border-radius:4px;border:1px solid #AAAAAA;">
</select>

Upvotes: 1

Related Questions