Search code examples
angulartypescriptangular-decorator

ERROR TypeError: Cannot read property 'seatsavailable' of undefined


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]


Solution

  • 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 !!