0

I am building a timer app/component and I cannot find my error. It sounds like this: Cannot set property startAt of undefined. Don't know where is an error because I defined it in my dashboard component. Any ideas where is an error and how can I fix it? I post most of my code, maybe error is somewhere else.

This is my code:

My dashboard.ts file

export class DashboardComponent implements OnInit {
  appUser: User;
  clients: Client[] = [];
  today: Date = new Date(2019, 9, 25, 12, 23);     // Defualt todays time;

  @ViewChild('counter', {read: CounterComponent, static: false})
  private counter: CounterComponent;

  counterState = 'counter is ticking';
  ngOnInit() {
    this.appUser = this.userS.currentUser;
    this.clients = this.clientService.getUserClients()
    .sort((a, b) => {
      return (new Date(a.registrationDate) as any) - (new Date(b.registrationDate) as any);
    });
    this.counter.startAt = 120;   // Here I am defining it
    this.counter.counterState.subscribe((msg)=>{
      if(msg==='COMPLETE') {
        this.counterState = 'counter has stopped';
      }
    });
    this.counter.start();
  }
}

My dashboard.html file

<counter #counter></counter>

My Mycounter.ts file

@Component({
  selector: 'counter',
  templateUrl: './counter.component.html',
  styleUrls: ['./counter.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class CounterComponent  {
  @Input()
  startAt:number = 1;

  @Input()
  showTimeRemaining = true;

  @Output()
  counterState = new EventEmitter();

  currentValue = '';

  private currentSubscription: Subscription;

  constructor(private changeDetector: ChangeDetectorRef) { }

  public start() {
    this.currentValue = this.formatValue(this.startAt);
    this.changeDetector.detectChanges();

    const t: Observable<number> = interval(1000);
    this.currentSubscription = t.pipe(take(this.startAt))
.pipe(  // not sure about this place but using only map but else it says 
        // Property 'map' does not exist on type 'Observable<number>'
  map(v =>    this.startAt - (v + 1))).subscribe(v => {
        this.currentValue = this.formatValue(v);
        this.changeDetector.detectChanges();
      }, err => {
        this.counterState.error(err);
      }, () => {
        this.currentSubscription.unsubscribe();
        this.currentValue = '00:00';
        this.counterState.emit('COMPLETE');
        this.changeDetector.detectChanges();
      });
  }

  private formatValue(v) {
  const minutes = Math.floor(v / 60);
          const formattedMinutes = '' + (minutes > 9 ? minutes : '0' + minutes);
          const seconds = v % 60;
          const formattedSeconds = '' + (seconds > 9 ? seconds : '0' + seconds);

  return `${formattedMinutes}:${formattedSeconds}`;
  }
}

Dharman
  • 30,962
  • 25
  • 85
  • 135
Dignity Dignity
  • 151
  • 2
  • 11
  • Hmm, this is weird. You are defining `counter` as a `static: false` but you are trying to access it in `ngOnInit` and it is defined? That shouldn't be the case... Maybe try using `static: true` or move the "counter" code to the `ngAfterViewInit`... Actually, that is exactly the issue, `counter` is not defined and you are trying to set property `startAt` of undefined... – miselking Sep 22 '19 at 20:48
  • On what line does the error occur? If it's on the same line as the comment "Here I am defining it", then that makes perfect sense that you would get that error there. – kshetline Sep 22 '19 at 20:59

1 Answers1

1

You can solve this in 2 ways: First, you can use static: true to make counter available in ngOnInit:

@ViewChild('counter', {read: CounterComponent, static: true})
private counter: CounterComponent;

This way you will be able to access counter variable in ngOnInit unless there is a structural directive preventing it (like *ngIf for example, more on that here and here).

The second way is to move counter code to ngAfterViewInit (there, the counter variable will be resolved and you won't get the error):

@ViewChild('counter', {read: CounterComponent, static: false})
private counter: CounterComponent;

ngAfterViewInit() {
    this.counter.startAt = 120;
    this.counter.counterState.subscribe((msg)=>{
      if(msg==='COMPLETE') {
        this.counterState = 'counter has stopped';
      }
    });
    this.counter.start();
}

Hope this helps...

miselking
  • 3,043
  • 4
  • 28
  • 39