1

I'm using a TypeScript class to define a controller in AngularJS:

class TrialsCtrl {
    constructor(private $scope: ITrialsScope, private ResourceServices: ResourceServices) {
        this.loadTrials();
    }

    loadTrials() {
        console.log("TrialsCtrl:", this);        
        this.Trial.query().then((result) => {
            this.$scope.Trials = result;
        });
    }

    remove(Trial: IRestTrial) {
        this.ResourceServices.remove(Trial, this.loadTrials);
    }
}
angular.module("app").controller("TrialsCtrl", TrialsCtrl);

I'm refactoring common controller methods into a service.

class ResourceServices {    
    public remove(resource, reload) {     
        if (confirm("Are you sure you want to delete this?")) {
            resource.remove().then(() => {
                reload();
            });
        }
    }
}

angular.module("app").service("ResourceServices", ResourceServices);

The console log shows that this is referencing the window context when I want it to be TrialsCtrl. My problem is that the reload() method needs to run in the context of TrialsCtrl, so that it can access this.Trial and this.$scope. How can I tell the reload() method to set this as the TrialsCtrl? Or is there some other workaround I should be using for this kind of thing?

Shaun
  • 2,012
  • 20
  • 44

2 Answers2

1

Have you tried:

this.ResourceServices.remove(Trial, this.loadTrials.bind(this));

or

this.ResourceServices.remove(Trial, () => this.loadTrials());
Artur Górski
  • 2,365
  • 2
  • 15
  • 14
  • `this.loadTrials.bind(this)` works, thanks! I tried `() => this.loadTrials` as well, but it seemed to never actually run the callback. – Shaun May 12 '16 at 20:09
  • Ok, I've missed brackets in my second example it should be `this.ResourceServices.remove(Trial, () => this.loadTrials());`both methods should keep origin context for passed callback. – Artur Górski May 12 '16 at 20:13
1

For methods that are supposed to be passed as callbacks (as with this.loadTrials) it is preferable to define them as arrows,

loadTrials = () => { ... }

So they keep the context whether Function.prototype.bind is used or not.

Alternatively, a decorator may be used on the method (like core-decorators @autobind) to bind a method while still defining it on class prototype:

@autobind
loadTrials() { ... }
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • Thanks, that works as well. As I was looking for answers I came across this one: http://stackoverflow.com/questions/14471975/how-can-i-preserve-lexical-scope-in-typescript-with-a-callback-function/21386201#21386201 Your answer is very similar to **Option 5**, presented in the second answer. Do you think these questions are similar enough to be considered duplicates? – Shaun May 12 '16 at 20:22
  • Yes, they are. Almost every reasonable question has been already discussed on SO. Added a decorator solution, I'm quite sure it wasn't mentioned in the earlier question. – Estus Flask May 12 '16 at 20:33