Starting out with Typescript and KnockoutJS together and I've hit on a bug I can't reason out yet. HTML looks as follows:
<div class="panel panel-body">
<div class="list-group" data-bind="foreach: Items()">
<a href="#" class="list-group-item"
data-bind="text:Name, click: $parent.SetCurrent">
</a>
</div>
</div>
Typescript as follows:
/// <reference path="knockout.d.ts"/>
/// <reference path="jquery.d.ts" />
module ViewModels {
export class ItemViewModel {
public Name: KnockoutObservable<string>;
constructor(name: string) {
this.Name = ko.observable(name);
}//constructor
}
export class MainViewModel {
public SelectedItem: KnockoutObservable<ItemViewModel>;
public Items: KnockoutComputed<Array<ItemViewModel>>;
constructor() {
this.SelectedItem = ko.observable<ItemViewModel>();
this.Items = ko.computed({
owner: this,
read: () => {
return this.get_items();
}
});
}
//TODO: replace this with knockout.mapping plugin transforms
private convert_from_model(items_model) {
var arr = new Array<ItemViewModel>();
var owner = this;
items_model.forEach(function (item) {
var d = new ItemViewModel(item.name);
arr.push(d);
});
return arr;
}
private get_items(): Array<ItemViewModel> {
var items = [{ "name": "AAAA" }, { "name": "BBBB" }, { "name": "CCCC" }, { "name": "DDDD" }];
var items_c = this.convert_from_model(items);
return items_c;
}
public SetCurrent(item: ItemViewModel) {
this.SelectedItem(item);
}
}
}
window.onload = () => {
ko.applyBindings(new ViewModels.MainViewModel());
};
The problem is setting the current item on click event.
public SetCurrent(item: ItemViewModel) {
this.SelectedItem(item);
}
click event correctly calls SetCurrent, but the 'this' is of type ItemViewModel not MainViewModel as it should be. Am I missing something obvious?
Here's a VS2013 solution with everything to repro the problem.
Thanks
click: $parent.SetCurrent
Knockout always invokes event handlers with this
set to the current view model. This particular binding means (to Knockout) "Invoke $parent.SetCurrent
with the current view model as this
".
The simplest fix is to use an arrow function to always have the correct this
// Change the definition of SetCurrent like so:
public SetCurrent = (item: ItemViewModel) => {
this.SelectedItem(item);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With