1

I have an mvc application where I am writing the client side code in TypeScript, as well as using several well known javascript libraries, including knockout, amplifyjs, and requirejs. I have ran into a situation where the expected behavior isn't what happens.

export class OrganizationOverviewViewModel{

    openedAssessments = ko.observableArray();
    availableSurveys = ko.observableArray();

    organizationAgentId = ko.observable();
    organizationName = ko.observable();

    selectedSurvey = ko.observable();

    public addSurvey() {
        if (this.selectedSurvey() === undefined) {
            mh.MessageHub.showError("Please Select a Survey", "what");
        }
        else {
            // we can do the post.
            // get the selected survey
            var surveyId = this.selectedSurvey();
            // call the server to add the survey

            amplify.request("addSurveyToOrganization", {
                "surveyId": surveyId,
                "organizationAgentId": this.organizationAgentId()
            },
            function (data) {
                var context = ko.contextFor($('#mainContent')[0]).$data;
                context.openedAssessments.push({ surveyId: data.SurveyId, SurveyName: data.SurveyName, NumberOfResponses: data.ResponseCount });
                context.availableSurveys.remove(function (item) { return item.SurveyId == surveyId; });
            });
        }
    }

}

The problem is in addSurvey(). Inside the amplify request, I expected the 'this' keyword to still point to the instance of the class. Instead, it pointed to the entire window. I had a workaround, which was to use knockout to go get the context from the DOM, but this really doesn't seem like it's a good idea.

Is there a better way of handling this using typescript?

Josh
  • 776
  • 6
  • 20
  • To understand `this` a bit better in TypeScript : https://www.youtube.com/watch?v=tvocUcbCupA&hd=1 – basarat Apr 21 '14 at 05:43

2 Answers2

5

In Typescript the "this" keyword follows javascript semantics rather than the semantics of OO languages like C#.... (for now?)

The only place "this" correctly points to the object is through the constructor. So you will need to write something like so:

export class OrganizationOverviewViewModel{

    public addSurvey;

    constructor() {
        this.addSurvey = () => {
           // you can safely use 'this' in here
           ...
        }
    }
    :
}

Edit : The new version (0.9.1) lets you use "this" for lambda field initializers (NOT functions). So you can use the following which translates to the code above.

export class OrganizationOverviewViewModel{

    public addSurvey = () => {
        // you can safely use 'this' in a field initializer
    }

    public badSurvey_dont_use_this() {
        // 'this' is probably not the 'this' you're looking for
    }
}
Ray
  • 2,974
  • 20
  • 26
0

Tak a look at TypeScript and Knockout binding to 'this' issue - lambda function needed? - its the same approach Ray mentions which seems to be correct

Community
  • 1
  • 1
Slawek
  • 2,592
  • 1
  • 24
  • 26