1

In this basic app.component.ts sample snippet (created only for learning purposes), I've observed that if I use a setInterval block in the constructor, string-interpolating a template variable from that block is not gonna work.

I know this is not a meaningful example but it does show the issue:
What technique should be used here so we can update {{ timeDisplay }} area in the template?

This looks like a scope issue. Can this be solved thru a global variable? Or what's a better way to tackle this capability?

import { Component, OnInit } from '@angular/core';

export class Hero {
  id: number;
  name: string;
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  timeDisplay: string;

  constructor () {
    this.timeDisplay = 'time will be displayed right here.';

    // set timer
    setInterval(
        function(){
            this.timeDisplay = new Date(); // this does not create an error but does not do anything neither. it is most likely timeDisplay variable is not in the constructor's scope
        },
        1000
    );

  }
Average Joe
  • 4,521
  • 9
  • 53
  • 81

1 Answers1

2

The problem is that you're losing context for this here since function expressions don't preserve context:

// set timer
setInterval(
    function(){
        this.timeDisplay = new Date(); // this does not create an error but does not do anything neither. it is most likely timeDisplay variable is not in the constructor's scope
        ^^^ - points to global object, not `AppComponent`
    },
    1000
);

change it to arrow functions that preserve the context:

// set timer
setInterval(
    () => {
        this.timeDisplay = new Date();
    },
    1000
);

For more information see this answer.

Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488
  • you are right on. that's the answer I was looking for but I still do not get why your approach works so the `this` works there! Can you elaborate the working code a little bit more? ALL I CAN SEE THERE is that you are using an arrow function. Is that it? – Average Joe Sep 16 '17 at 15:17
  • @AverageJoe, I've added a bit more explanation. Yes, arrow function preserves context for `this` and it's that's required. The answer I linked will give you all the information you need to understand why it works – Max Koretskyi Sep 16 '17 at 15:19
  • There is one more problem in the code; I happened to assign an object ( the date object that is ) onto a string. So as a result, we do not get a valid run time off of the current code. In Angular, is there a temporary type conversion on the fly like we do in PHP: ex: (int) '5'. what can we do to assign the string representation of the new Date response ( like it would show in an alert )? alert(new Date() ) works. – Average Joe Sep 16 '17 at 15:52
  • _So as a result, we do not get a valid run time off of the current code._ what do you get rendered in HTML? – Max Koretskyi Sep 16 '17 at 15:56
  • The err was `Type 'Date' cannot be converted to type 'string'.`. TSC dies there, & it does not want to compile. I had this in the HTML but it does not go that far: {{ timeDisplay | date: 'dd/MM/yyyy' }} – Average Joe Sep 17 '17 at 21:19
  • so change `timeDisplay: string;` to `timeDisplay: Date;` – Max Koretskyi Sep 18 '17 at 04:59