0

I have a component that populates an Object array in its ngInit() method from a service which I then use the contents of in my HTML template.

My problem is I can use this data fine in the HTML template but if I try to use this same Object array in my TypeScript file I will get an undefined error.

Below is a simplified code example of my problem:

@Component({
  selector: 'booking',
  template: `  
    <div *ngFor="let r of requestedBookings">
      <label>Requested on {{r.created | date: 'd MMM H:mm'}}</label>
    </div>
  `
})

export default class BookingComponent {

    requestedBookings: Object[];

    constructor(private bookingService: BookingService) {
      
    }
    
    ngOnInit() {
      
      this.getRequestLog();
      
      // Cannot read property 'length' of undefined error
      // console.log(this.requestedBookings.length);
      
    }
    
   
    private getRequestLog(): void {
      
      this.bookingService.getRoomRequestBooking(1,1,1)
        .subscribe(data => this.requestedBookings = (data as any))
        .results, err => {
          console.log(err);
        }

}

Why is it in the above example I can use the requestedBookings array as expected in the HTML template but inside the TypeScript file I receive undefined errors?

6
  • 6
    Because getRequestLog is asynchronous, and thus this.requestedBookings.length is running before the bookings are returned. Commented Jul 26, 2017 at 2:32
  • @Rob is correct. requestedBookings: Object[]; is not an instantiation, it's a type declaration and is ambient. When ngOnInit runs, your variable is not instantiated. requestedBookings: Object[] = []; would allow the console log to execute. Commented Jul 26, 2017 at 2:35
  • So how can I ensure that getRequestLog() has completed before I access the array? Commented Jul 26, 2017 at 2:36
  • @ScottMackenzie Depends what you mean by completed, since you're subscribing to a stream, it may be constantly changing. You'll want to return the observable from getRequestLog and then subscribe to it to do your work. Alternatively, you could collapse the observable to a promise, return the promise, and then write something like getRequestLog().then(f => ...) Commented Jul 26, 2017 at 2:37
  • Thanks for your help identifying the asynchronous problem. I added an answer showing how I fixed my issue. Commented Jul 26, 2017 at 4:50

2 Answers 2

2

IMHO the correct way should be something like:

ngOnInit() {  
this.getRequestLog();
}

private getRequestLog(): void {
  this.bookingService.getRoomRequestBooking(1,1,1)
    .subscribe((data)=>{
     this.requestedBookings = data;
     console.log(this.requestedBookings.length);
    })
    .results, err => {
      console.log(err);
    }
}

As explained before, the call to getRoomRequestBooking is async, so you should not expect it will finish before calling the console.log. Instead, you should use the requestedBookings.length value in a place where you do know it will exist. Hope it helps!!

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks I ended up doing very similar.
0

I fixed this issue by using this constructor from the subscribe method. the complete parameter event happens after successful completion.

  subscribe(next?: (value: T) => void, 
            error?: (error: any) => void, 
            complete?: () => void): Subscription;

Code is as follows:

ngOnInit() {  
  this.getRequestLog();
}

private getRequestLog() {

  this.bookingService.getRoomRequestBooking(this.date, this.level, this.room)
    .subscribe(
      data => this.requestedBookings = (data as any).results,
      err => {
        console.log(err);
      },
      () => console.log(this.requestedBookings.length));

}

2 Comments

could you check @DavidAlejandroReyesMilián answer ? which was answered 1hour before.
@k11k2 Yes not quite the same.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.