0

I'm trying to get a hang of routing in ng2 and I faced a strange issue. I tried to set a timeout to navigate me back to '/' when a user reaches '/home'.

This works:

export class HomeComponent implements OnInit {

    constructor(private router: Router) { }

    ngOnInit() {
        setTimeout(() => {this.router.navigate(['/']);}, 2000);
    }

}

But this does not:

export class HomeComponent implements OnInit {

    constructor(private router: Router) { }

    ngOnInit() {
        setTimeout(function () {this.router.navigate(['/']);}, 2000);
    }

}

It fails with - EXCEPTION: Cannot read property 'navigate' of undefined

To make it work, I have to change it to:

export class HomeComponent implements OnInit {

    constructor(private router: Router) { }

    ngOnInit() {
        var _router = this.router;
        setTimeout(function (_router) {_router.navigate(['/']);}, 2000, _router);
    }

}

Incidentally, this is how TypeScript compiles () => {} into. But does it not know that this is not available within setTimeout() in the second code snippet? Is this a limitation of TypeScript?

Sterex
  • 938
  • 1
  • 12
  • 24
  • 5
    `() => {}` is an ECMAScript 6 [Arrow Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions): "An arrow function expression has a shorter syntax than a function expression and *does not bind its own this*, arguments, super, or new.target. Arrow functions are always anonymous. These function expressions are best suited for non-method functions, and they cannot be used as constructors." The changes works because there is no reliance on `this`. – user2864740 Jan 06 '17 at 06:55
  • 1
    Arrow functions inherit `this` from their surrounding scope, while old-style functions don't inherit `this` from their surrounding scope. The difference is important because of the ["this" problem with `setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout#The_this_problem). – 4castle Jan 06 '17 at 06:57
  • I agree with both @user2864740 and -4castle in that they are concerns with the way JavaScript handles scope. But isn't TypeScript supposed to work around these? – Sterex Jan 06 '17 at 06:58
  • 3
    See http://stackoverflow.com/questions/34361379/arrow-function-vs-function-declaration-expressions-are-they-equivalent-exch – user2864740 Jan 06 '17 at 06:58
  • 1
    Thank you. http://stackoverflow.com/questions/34361379/arrow-function-vs-function-declaration-expressions-are-they-equivalent-exch - this answered my query. I have voted the question be closed as a duplicate. – Sterex Jan 06 '17 at 07:01
  • Since these ways of creating a function have different usages why would typescript try to "fix" it in any way? – Sami Kuhmonen Jan 06 '17 at 07:03
  • @SamiKuhmonen - Because it "fixes" it when `() => {}` is used but not when `function () {}` is used. – Sterex Jan 06 '17 at 07:04

1 Answers1

5

For Typescript, this is the Object, which represented like $scope variable in Angular 1.x. If you write native JavaScript in the Scope of Typescript logic then it will consider this as an window object. So you will not able to access typescript object this anymore.

To overcome this, I have a simple idea to be applied whenever you use JavaScript code:

export class HomeComponent implements OnInit {
   constructor(private router: Router) { }
   ngOnInit() {
      let that = this; // Assign scope variable to temporary variable: that 
      setTimeout(function () {that.router.navigate(['/']);}, 2000); // Use that particular variable anywhere in the method scope instead of Scope variable
   }
}

Note: Typescript doesn't encourage you to use JavaScript in the code. Because ts linting is already generating JavaScript output. But still if you want to use JavaScript, then this is the only solution.

Krunal
  • 647
  • 6
  • 14
  • Are you saying there is a conflict of scope for `this` when I use `function () {}`? Which is why TypeScript leaves it as is? – Sterex Jan 06 '17 at 07:06
  • 1
    Correct. Typescript doesn't encourage you to use JavaScript in the code. Because ts linting is already generating JavaScript output. But still if you want to use JavaScript, then this is the only solution that I found. Hope this helps. :) – Krunal Jan 06 '17 at 07:09