"this" issue when using viewmodel in typescript and knockout

asp.net-mvc, knockout.js, typescript

Solution

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.

Problem

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> } ```

Original source