Computed Observables in TypeScript

1,808 views
Skip to first unread message

stijnh...@gmail.com

unread,
Jul 16, 2013, 4:15:15 AM7/16/13
to knock...@googlegroups.com
Is there any way to have access to this in computed observables, other than setting the implementation in the constructor?
Arrow functions are not possible, passing this as the second parameter is not possible, using self is not possible.

I'm also wondering if this is a TypeScript issue or a Knockout one?

Brian Zengel

unread,
Jul 16, 2013, 8:16:28 AM7/16/13
to knock...@googlegroups.com
I'm going to assume you are constructing your view model with a constructor function and that you are defining your computed inside the constructor. If so, I am also assuming you want "this" to represent the instance of your view model. If this is the case, then using an arrow function to define your computed will automatically create a "var _this = this;" statement at the top of the scope of that arrow function in the JavaScript. Then all references to "this" inside your arrow function will be translated to "_this".

If you want "this" to be a different value than your view model, then define your computed using an anonymous function to prevent the "this" to "_this" translation from occurring and pass what you want "this" to be as your second parameter.

-Brian

CodeRenaissance

unread,
Jul 16, 2013, 8:26:50 AM7/16/13
to knock...@googlegroups.com, stijnh...@gmail.com
Its been a bit since I checked into type script but my understanding was that valid javascript is valid type script. Type script adds typing, interfaces, modules and other goodies, but you're free to use as much or as little of those features as fits your needs. What you're running into is a limitation of javascript in the scope of how knockout works.

This won't work because you can't reference a because it doesn't exist yet (computeds are executed when defined by default).
var a = { b:ko.observable(5), c: ko.computed({ read:function(test){ return this.b(); }, owner:a}) };

This works because deferEvaluation keeps c from being evaluated immediately:
var a = { b:ko.observable(5), c: ko.computed({ read:function(test){ return this.b(); }, owner:a, deferEvaluation:true}) };

This works because a is defined before being referenced:
var a = {}; a.b = ko.observable(5); a.c = ko.computed({ read:function(test){ return this.b(); }, owner:a });
Hope this helps.

stijnh...@gmail.com

unread,
Jul 16, 2013, 4:33:50 PM7/16/13
to knock...@googlegroups.com, stijnh...@gmail.com
While creating some samples to post here, I discovered something odd. Model code:

/// <reference path="knockout.d.ts" />

class viewmodel
{
   
public foo: KnockoutObservable<string> = ko.observable();

   
public bar: KnockoutObservable<string> = ko.observable();

   
public baz: KnockoutComputed<string> = ko.computed(() =>
   
{
       
return this.foo() + " " + this.bar();
   
});

    constructor
(foo: string, bar: string)
   
{
       
this.foo(foo);

       
this.bar(bar);
   
}
}

The TypeScript compiler will complain about the usage of this
 'this' cannot be referenced in initializers in a class body.
Looking up the error, I found http://notebookheavy.com/2012/10/03/typescript-and-knockout-computed/ discussing this issue. There are also some posts on StackOverflow that I can't find right now, with answers that also suggest to implement the computed in the constructor.
 
However, to my surprise, it actually compiles and runs without any problems.
So this looks like a TypeScript issue. I found an existing bug report about this: http://typescript.codeplex.com/workitem/846




Op dinsdag 16 juli 2013 10:15:15 UTC+2 schreef stijnh...@gmail.com het volgende:
Reply all
Reply to author
Forward
0 new messages