3

I have 2 components, ComponentA & ComponentB, comp b is a child to comp a. ComponentB basically takes input from ComponentA & generates view. This input is obtained from a rest call. So I have wrapped my component b selector in an *ngIf. In this selector I also have a viewchild attached to it.

So basically, what I am assuming is that when ComponentB is completely rendered, I want to execute some code using my viewchild reference. This code is written in ngAfterViewInit() inside ComponentA. But when I try to access this.viewChildReference, it says undefined.

ComponentA.html

<div *ngIf="dataAvailable">
    <componentb #viewChildReference [data]="dataFromComponentA"></componentb>
</div>

ComponentA.ts

// skipping boiler code for brevity

class {
    dataAvailable = false;
    @ViewChild('viewChildReference') viewChildReference: ChildComponentModule;

    ngOnInit() {
        // fetch data from rest
        dataAvailable = true;
    }

    ngAfterViewInit() {
        this.viewChildReference.somemethod();
    }
}

ComponentB.html

// Use data from parent component and generate view

How can I solve this? What is wrong with my current approach? Please help as I am stuck up at this point..

UPDATE:

This question is not duplicate, as I have tried other solutions as suggested in comments in this question, like emitting events & other answers. Still I am facing issues, kindly unmark this as duplicate.

Community
  • 1
  • 1
csfragstaa
  • 145
  • 1
  • 2
  • 9
  • Possible duplicate of [Angular 2 @ViewChild in \*ngIf](https://stackoverflow.com/questions/39366981/angular-2-viewchild-in-ngif) – ConnorsFan Jan 30 '19 at 15:01

2 Answers2

2

You said you're fetching the data from a rest api. That's asynchronous. The call to ngAfterViewInit is synchronous, which means by the time it's called, your data is still not available, thus the component won't be rendered because of the ngIf. You need to call this.viewChildReference.somemethod(); once your http call completes. Something like this:

this.myService.someAPiCall().subscribe(data => {
    this.data = data;
    this.viewChildReference.somemethod();
})
Christian
  • 2,676
  • 3
  • 15
  • 25
  • And also, `@ViewChild('viewChildReference') viewChildReference: ChildComponentModule;` does not return `ChildComponent` reference unless specified like `@ViewChild('viewChildReference',{read: ChildComponent}) viewChildReference: ChildComponent;` And I think the type `ChildComponentModule` is wrong as OP is getting reference to the module but not the component. – Harun Yilmaz Jan 30 '19 at 14:50
  • Yes, but http service will provide the data to child component and only after child component has completely rendered, then I want to execute the `somemethod`. sample implementation of somemethod: somethod() { return this.someProperty; } – csfragstaa Jan 30 '19 at 14:55
  • @csfragstaa why don't you use an @ Output and emit the value during ngOnInit of the child component? – Christian Jan 30 '19 at 15:19
  • @Christian, believe me bro I tried that as well, even taht is failing, so I tried to emit the event from ngAfterViewInit in child component, even that is not working :/ – csfragstaa Jan 30 '19 at 15:21
2

You can try

@ViewChild('viewChildReference') 
set viewChildReference(v) {
   // v is the viewChild, handle your logic here
   // if v is defined.... 
}

demo https://stackblitz.com/edit/angular-egh5dg, btw, this approach will always sync up with ngIf, if you use other approaches, viewChildReference might have stale reference, say, if you subscribe to api calls, but angular needs time to update viewChildReference and it could happen this view update is behind subscription.

ABOS
  • 3,723
  • 3
  • 17
  • 23