M.Powell M.Powell - 1 month ago 22
TypeScript Question

KnockoutJs binding issue on select list

I'm using Typescript with KnockoutJs and I am having issues with binding the optionsText and optionsValue. The model is:

export interface LanguageProxy {
ID: number;
Name: string;
Code: string;
IsSparse: boolean;
HasAudio: boolean;
ReadsRightToLeft: boolean;
IsAsian: boolean;
ShortCode: string;
LongCode: string;
CultureCode: string;
IsEnabled: boolean;
IsCustom: boolean;
}


we are setting up the binding as (response being a response from a web service call):

var langs = ko.observableArray([]);
response.LanguageProxyListResult.forEach(lang => {
langs.push(ko.observable(lang));
});

this.Languages = langs;
ko.applyBindings(this, jQuery("#QuickSearchContainer")[0]);


and we are binding using the following HTML below:

<select name="ddlLanguage" id="ddlLanguage" class="LanguageList"
data-bind="options: Languages,
optionsText: 'Name',
optionsValue: 'ID',
optionsCaption: 'Choose...',
optionsAfterRender: function (e) { jQuery('#ddlLanguage')[0].selectedIndex = 1;}">

</select>


The data binds correctly, removing the optionsText and optionsValue returns the list of [object] [OBJECT], but when adding the properties of optionsText and value it sets up a blank list.

Looking at a knockoutJs context debugger for chrome, the data appears correctly in the element (under $data.Languages.Symbol(_latestValue) and the parsed context) . Is there something fundamentally I am doing wrong?

Answer

I don't think the options binding supports observables in the array.

If you replace langs.push(ko.observable(lang)); by just langs.push(lang);, it should work.

There's no real point in wrapping an object in an observable when it's in an observable array.

Reproduction of problem, note that the second select will throw an error.

var opts = ko.observableArray([
  { name: "Option 1" },
  { name: "Option 2" }
]);


var obsObs = ko.observableArray([
  ko.observable({ name: "Option 1" }),
  ko.observable({ name: "Option 2" })
]);


ko.applyBindings({
  opts: opts,
  obsObs: obsObs
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<select data-bind="options: opts, optionsText: 'name'"></select>
<select data-bind="options: obsOpts, optionsText: 'name'"></select>