5
votes

I am trying to pass a map, which come from an api, from parent to child component, in angular 7.

parent.ts:

export class AppComponent {
  title = 'taurs-frontend';
  categories: any;
  isLoggedIn = false;

ngOnInit(){
    this.roomDataService.getData(`${environment.api_url}/api/Categories`)
    .subscribe(categories => {
      this.categories=categories
    }); 
  }

parent.html:

 <app-room-card [categories]="categories"></app-room-card> 

child.ts:

@Component({
  selector: 'app-room-card',
  templateUrl: './room-card.component.html',
  styleUrls: ['./room-card.component.css']
})
export class RoomCardComponent implements OnInit {
    @Input('categories') catname: any;

    ngOnInit() {
        console.log('aaa'+ this.catname);
    }
// ..
}

When I try to log the variable catname, it is undefined. If I try to import variable title from the parent, everything works properly. How can I pass categories to the child, filling it with the values from the API call?

4
Have you tried using ngIf to only render the child component when the API call is resolved? Otherwise you are passing an undefined value until the resolution happens. Also you could try using a different lifecycle hook that would detect the changes to the value at initialization and on changes. - Alexander Staroselsky

4 Answers

16
votes

You are trying to pass asynchronous data to child component. You have different solutions to do that. For exemple, you can use ngOnChanges instead of ngOnInit:

ngOnChanges() {
    console.log('aaa'+ this.catname);
}

Another solution is to use *ngIf, in order to delay the initialization of posts components:

<app-room-card *ngIf="categories" [categories]="categories"></app-room-card>

Take a look at this link: https://scotch.io/tutorials/3-ways-to-pass-async-data-to-angular-2-child-components#toc-solution-2-use-ngonchanges

6
votes

Try changing your component code as,

export class RoomCardComponent implements OnInit {
   @Input() categories: any; 
   ngOnInit() {
   console.log('aaa'+ this.categories);
   }
}

and have *ngIf on the parent component just to make sure the data is passed to child once you get the response from your API

<app-room-card *ngIf="categories" [categories]="categories"></app-room-card> 
-1
votes

Maybe you should define your input in this way, so when the attribute is loaded immediately is updated in the child component:

  @Input('categories')
  set categories(value: any) {
    this._categories = value;
  }
-2
votes

I had the same issue, i fixed with a variable "loading" of type boolean;

export class AppComponent {
  title = 'taurs-frontend';
  categories: any;
  isLoggedIn = false;
  loading:boolean = false; -> // my variable

ngOnInit(){
    this.loading = true; -> // true when the request starts 
    this.roomDataService.getData(`${environment.api_url}/api/Categories`)
    .subscribe(categories => {
      this.categories=categories
      this.loading = false; // false with the request ends
    }); 
  }

So, in HTML

 <app-room-card *ngIf="!loading" [categories]="categories"></app-room-card> 
 // i used this variable to wait data of my parent component 

I hope this solves your problem or helps someone else.