See below for updated code
I'm trying to use knockout with typescript but it seems I'm not able to bind my typescript viewmodel to my view... it seems I have an issue with the this
but I don't understand why...
The this.UserList
is undefined when calling the Fill
method
Here is my viewModel:
module ViewModels {
export class UserViewModel {
constructor() {
this.UserList = ko.observableArray<KnockoutObservable<Models.User>>([]);
this.RemoveItem = <(user: KnockoutObservable<Models.User>) => void> this.RemoveItem.bind(this);
this.AcceptItem = <(user: Models.User) => void> this.AcceptItem.bind(this);
this.AddItem = <() => void> this.AddItem.bind(this);
}
public UserList: KnockoutObservableArray<KnockoutObservable<Models.User>>;
public Fill() {
$.ajax({
type: "POST",
url: "/Guest/LoadGuest/",
success: data=> {
$(data).each((index: any, item)=> {
var guest = new Models.User();
guest.FirstName = ko.observable(item.firstName);
guest.LastName = ko.observable(item.lastName);
guest.IsNew = ko.observable(false);
this.UserList.push(ko.observable(guest));
});
}
});
}
public AddItem() {
var guest = new Models.User();
guest.FirstName = ko.observable("");
guest.LastName = ko.observable("");
guest.IsNew = ko.observable(true);
this.UserList.push(ko.observable(guest));
}
public AcceptItem(user: Models.User) {
user.IsNew = ko.observable(false);
}
public RemoveItem(user: KnockoutObservable<Models.User>) {
this.UserList.remove(user);
}
}
}
Here is my View:
<table>
<thead>
<tr><th>Prénom</th><th>Nom de famille</th></tr>
</thead>
<tbody data-bind="foreach: UserList">
<tr data-bind="if:IsNew">
<td><input type="text" data-bind="text: FirstName" /></td>
<td><input type="text" data-bind="text: LastName" /></td>
<td><a data-bind="click:$parent.AcceptItem">OK</a><a data-bind="click:$parent.RemoveItem">Annuler</a></td>
</tr>
<tr data-bind="if:!IsNew">
<td data-bind="text: FirstName"></td>
<td data-bind="text: LastName"></td>
<td></td>
</tr>
</tbody>
</table>
<a id="AddGuest" data-bind="click:AddItem">Add</a>
@section scripts{
<script src="~/Scripts/models/ModelBase.js"></script>
<script src="~/Scripts/models/User.js"></script>
<script src="~/Scripts/viewmodels/UserViewModel.js"></script>
<script>
var vm = new ViewModels.UserViewModel();
vm.Fill();
ko.applyBindings(vm);
</script>
}
Here is my model:
module Models{
export class User extends Models.ModelBase {
constructor() {
super();
}
public FirstName: KnockoutObservable<string>;
public LastName: KnockoutObservable<string>;
public Age: KnockoutObservable<Age>;
}
export class Age {
public ID: KnockoutObservable<number>;
public Description: KnockoutObservable<string>;
}
}
New working code for helping purposed:
ViewModel:
module ViewModels {
export class UserViewModel {
constructor() {
}
public UserList: KnockoutObservableArray<Models.User> = ko.observableArray<Models.User>([]);
public Fill = () => {
$.ajax({
type: "POST",
url: "/Guest/LoadGuest/",
success: data=> {
for (var i = 0; i < data.length; i++) {
var item = data[i];
var guest = new Models.User();
guest.FirstName(item.firstName);
guest.LastName(item.lastName);
guest.Age().Description("Test Age");
guest.IsNew(false);
this.UserList.push(guest);
}
}
});
}
public AddItem = () => {
var guest = new Models.User();
guest.FirstName = ko.observable("");
guest.LastName = ko.observable("");
guest.IsNew(true);
this.UserList.push(guest);
}
public AcceptItem = (user: Models.User) => {
user.IsNew(false);
}
public RemoveItem = (user: Models.User) => {
this.UserList.remove(user);
}
}
}
Model:
module Models{
export class ModelBase{
constructor() {
this.IsNew = ko.observable(false);
}
public IsNew: KnockoutObservable<boolean>;
}
export interface IUser {
FirstName: KnockoutObservable<string>;
LastName: KnockoutObservable<string>;
Age: KnockoutObservable<Age>;
}
export class User extends Models.ModelBase implements IUser {
constructor() {
super();
this.FirstName = ko.observable("");
this.LastName = ko.observable("");
this.Age = ko.observable(new Age());
}
public FirstName: KnockoutObservable<string>;
public LastName: KnockoutObservable<string>;
public Age: KnockoutObservable<Age>;
}
export class Age {
constructor() {
this.ID = ko.observable(null);
this.Description = ko.observable("");
}
public ID: KnockoutObservable<number>;
public Description: KnockoutObservable<string>;
}
}
View:
<table>
<thead>
<tr><th>Prénom</th><th>Nom de famille</th><th>Age</th></tr>
</thead>
<tbody data-bind="foreach: UserList">
<tr data-bind="ifnot:$data.IsNew">
<td data-bind="text: FirstName"></td>
<td data-bind="text: LastName"></td>
<td data-bind="text: Age().Description"></td>
</tr>
<tr data-bind="if:$data.IsNew">
<td><input type="text" data-bind="value: FirstName" /></td>
<td><input type="text" data-bind="value: LastName" /></td>
<td><input type="text" data-bind="value: Age().Description" /></td>
<td><a data-bind="click:$root.AcceptItem">OK</a><a data-bind="click:$root.RemoveItem">Annuler</a></td>
</tr>
</tbody>
</table>
<a id="AddGuest" data-bind="click:AddItem">Add</a>
@section scripts{
<script src="~/Scripts/models/ModelBase.js"></script>
<script src="~/Scripts/models/User.js"></script>
<script src="~/Scripts/viewmodels/UserViewModel.js"></script>
<script>
var vm = new ViewModels.UserViewModel();
vm.Fill();
ko.applyBindings(vm);
</script>
}
If you want this
to be bound to the UserViewModel
that then maybe use this approach:
module ViewModels {
export class UserViewModel {
UserList: KnockoutObservableArray<KnockoutObservable<Models.User>> = ko.observableArray<KnockoutObservable<Models.User>>([]);
Fill = () => {
$.ajax({
type: "POST",
url: "/Guest/LoadGuest/",
success: data => {
$(data).each((index: any, item)=> {
var guest = new Models.User();
guest.FirstName = ko.observable(item.firstName);
guest.LastName = ko.observable(item.lastName);
guest.IsNew = ko.observable(false);
this.UserList.push(ko.observable(guest));
});
}
});
}
AddItem = () => {
var guest = new Models.User();
guest.FirstName = ko.observable("");
guest.LastName = ko.observable("");
guest.IsNew = ko.observable(true);
this.UserList.push(ko.observable(guest));
}
AcceptItem = (user: Models.User) => {
user.IsNew = ko.observable(false);
}
RemoveItem = (user: KnockoutObservable<Models.User>) => {
this.UserList.remove(user);
}
}
}
Here's a TypeScript Playground to demo
You can read an explanation of the approach being used here: http://blogs.msdn.com/b/typescript/archive/2013/08/06/announcing-0-9-1.aspx (check "Better 'this' handling)
By the way, I suspect where you have KnockoutObservable<Models.User>
you should actually have Models.User
and when you have this.UserList.push(ko.observable(guest));
you actually should have this.UserList.push(guest);
. I haven't changed the code sample in case I missed something.
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