ERROR TypeError: Cannot read property 'seatsavailable' of undefined

1.4k Views Asked by At

I'm working in Angular 6 project with @Input and @Output decorators. I have Bookride Component as a parent component and RideDetails as a child component. I could successfully pass the data from my parent component to child component with @Input decorator, but when I tried to pass data from child component to parent component, I'm getting the following error in the console

"ERROR TypeError: Cannot read property 'seatsavailable' of undefined"

BookRide Component - HTML(Parent Component)

<tr *ngFor = "let book of shrides | filterpipe:filterargs" (click) = "message = book">
  <td>{{book.startloc}}</td>
  <td>{{book.destination}}</td>
  <td>{{book.seatsavailable}}</td>
  <td (click)="deleteProduct(book.id)"><a>DELETE</a></td>
  <td [routerLink] = "['/update-ride', book.id]" (click) = "update(book.id)"><a>UPDATE</a></td>

<app-ridedetails [cName] = "message" (onRegister)="courseReg($event)"></app-ridedetails>

In the console, Error appears in the above line as "ERROR TypeError: Cannot read property 'seatsavailable' of undefined at RestserviceService.push../src/app/restservice.service.ts.RestserviceService.updateRide2 (restservice.service.ts:84)"

BookRide Component - TS

export class RidedetailsComponent implements OnInit { 
seatsavailable: number;
courseReg(seatsavailable: number){
        console.log("Booking ID", seatsavailable);
        this.messages = `Booking Done. Your Booking name is : ${seatsavailable}`;
        this.render = !this.render;
}}

RideDetails Component - HTML(Child Component)

     <tr>
          <td>{{loadData?.id}}</td>
          <td>{{loadData?.name}}</td>
          <td>{{loadData?.car}}</td>
          <td>{{loadData?.seatsavailable}}</td>
          <td>{{loadData?.startloc}}</td>
          <td>{{loadData?.destination}}</td>
      </tr>

<button type="button" (click)="register(loadData.id, loadData.seatsavailable)" [ngClass] = "render ? 'btn-primary' : 'btn-danger'"> {{render == true ? 'Book!' : 'Cancel! Booked ride'}} </button>

RideDetails Component - TS

export class RidedetailsComponent implements OnInit {
  loadData:any;
  sendData: any;
  messages: any;
  render: boolean = true;
  seatsavailable: number;
  ride: Ride[];
  constructor(private restservice : RestserviceService) { }

  ngOnInit() {
  }

  @Input() set cName(sampleObject){
    this.loadData=sampleObject;
  }

  //Child to Parent Communication
  //Sending an event to BookrideComponent and hide the table using @Output Decorator
  @Output() onRegister = new EventEmitter();

  register(bookingID: string, seatsavailable: number, ride: Ride) {
    this.render = !this.render;
    this.onRegister.emit({seatsavailable} as Ride);
    this.messages = `Booking Done(ridedetails). Your Booking id: ${bookingID}`;
    console.log("After clicking on Book button, the seats available data in ride details component is", this.loadData.seatsavailable);
    // console.log("seats avaiable in ride details component", this.loadData.seatsavailable);
    if(this.loadData.seatsavailable === seatsavailable){
      console.log("this.loadData.seatsavailable", this.loadData.seatsavailable - 1);
      this.restservice.updateRide2(ride, seatsavailable).subscribe( shride => { this.loadData.seatsavailable - 1 });
    } 
   }
}

What I understood from RideDetails Component is that I have created a property called onRegister of type EventEmitter and attached @Output decorator which makes the property to send the data from child to parent component. Later inside register(), it emits the seatsavailable value back to parent component. So Once it reaches the parent component, it's ending up with the error.

Also in the courseReg() of BookRide Component, it's rendering the console as Your Booking name is : [object Object]

2

There are 2 best solutions below

6
On BEST ANSWER

Everything seems to be correct but i have some couple of changes in your code - I'm not sure that it will work but you can try

this.onRegister.emit(seatsavailable); if you are just sending seatsavailable from the child to parent just pass only the value it will be passed as an object.

Finally when you read your value you can read like this -

courseReg(event: any){
        console.log("Booking ID", event.seatsavailable);
        this.messages = `Booking Done. Your Booking name is : ${event.seatsavailable}`;
        this.render = !this.render;
}}

I'm sure this might work please try Thanks Happy coding !!

0
On

This error generally is due to the object not being resolved before the route is loaded. Therefore, we use the existential/safe operator book? (existential - does it 'exist'). If the error is caused by this, the best approach (unless you are using a loading spinner) is to utilise an Angular resolver, which resolves the data in your component before the route is loaded.

Here is a great article on Resolvers, if you are not familiar: https://codeburst.io/understanding-resolvers-in-angular-736e9db71267

Therefore your data will be available in the component before the route it resolved and you will not need to use ? to check if the data exists.