Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to init a component only when its tag is at `*ngIf=true`?

Update:
Günter Zöchbauer provided a very acceptable answer that works perfectly (and thank you!). But I still have a question to check if what I am doing is the correct way of getting the result I seek. Context is given below.
What I expect with my custom tag on the parent view, is that when the *ngIf condition is false, the component is not loaded at all (or maybe most part of it). Is it normal that even if it is not in the DOM (because the condition is false), it is still loaded? Is there a better way to embed components' templates (and the logic of their class) into a parent component's template?

Original post

I am new to Angular 2 and so far I'm having much fun developing a small song track metadata application based on the Spotify API.

TL;DR: How to init a component only when its corresponding HTML tag (defined with the selector property of @Component) if *ngIf="true"?


But of course I'm facing difficulties! I have this component, TrackDetailComponent, in the template of which I would like to include 2 other components. On clicking on a button, it would switch from one inner component to the other.
Here is how the template looks like (note that I only have developed one of the two inner components for now, so I used a placeholder in stead of the second one):

<div id="view">
    <tig-track-info *ngIf="childView == TrackDetailView.InfoView" [track]="track"></tig-track-info>
    <p *ngIf="childView == TrackDetailView.LyricsView">Here go the lyrics</p>
</div>

As you can see, my inner component (named TrackInfoComponent) has an input parameter. Here is an excerpt of that component:

@Component({
    selector: "tig-track-info",
    templateUrl: "app/components/track-info/track-info.component.html",
    styleUrls: ["app/components/track-info/track-info.component.css",
                "app/shared/animations.css"]
})
export class TrackInfoComponent implements OnInit {
    private _trackId: string = null;
    @Input() 
    track: Track = null;
    previewAudio: any = null; // The Audio object is not yet defined in TypeScript
    albumArtworkLoaded: boolean = false;
    ...
}

My real problem is not embedding the TrackInfoComponent inside the other one, but it is to sync them. The TrackDetailComponent calls an API asynchronously and then initializes the track property. But TrackInfoComponent also needs that track to be initialized in order to do its job or else I get a null reference exception (which is logical).

I tried setting the child component data in the ngOnInit() and setting the *ngIf of its parent's template to true only when the track is ready but it seems that ngOnInit() is called right away, even if the DOM element tig-track-info is not display with *ngIf.

I guess I could use events or my own init method in the child component, to call only when I'm ready, but I would like to know if there is a better way to do it using the Angular 2 component lifecycle hooks or any other method recommanded for that. Does anyone have any idea about that?

Thank you :-)

like image 963
Jeahel Avatar asked Jul 06 '16 17:07

Jeahel


People also ask

What is * ngIf and how does it work?

NgIflink. A structural directive that conditionally includes a template based on the value of an expression coerced to Boolean. When the expression evaluates to true, Angular renders the template provided in a then clause, and when false or null, Angular renders the template provided in an optional else clause.

Does ngIf trigger ngOnInit?

angular - Component initialization by ngIf does not trigger ngOnInit - Stack Overflow. Stack Overflow for Teams – Start collaborating and sharing organizational knowledge.

Does ngIf false destroy component?

Notice that the div element has an ngIf attribute. This attribute's value is the result of the contentVisible property. So if the contentVisible property is true, then the div element is created. Conversely, if the contentVisible property is false, then the div element is destroyed.

What happens when component is made visible again using ngIf?

Your div will be rendered and visible once the change detection is triggered. When a change is detected, the whole lifecycle is ran again. If you want to run something, you should hook on one of the events of the lifecycle.


1 Answers

You can use OnChanges which is called whenever an @Input() property value is changed by a template binding `[track]="..."

  export class TrackInfoComponent implements OnChanges {
    ngOnChanges(changes: SimpleChanges) {
      if(this.track) {
        ...
      }
    }
  }
like image 99
Günter Zöchbauer Avatar answered Nov 15 '22 23:11

Günter Zöchbauer