Reputation: 9005
I am surprised on how difficult it is to just pass an id to a component. Im sure I'm missing something but essentially ALL i want to do is be able to pass an id to a nested component. I have a parent container where my view consists of this, i am want to instantiate the 'asset' component with groupID = 6 :
template: `
<div class='another_page'></div>
<asset-manager [groupId]="6"></asset-manager>
<div class='another_page'></div>
`
I must have tried a half dozen ways based on various docs on the internet to no avail. Here is a cut from the actual AssetManager component
export class AssetManager implements AfterViewInit, OnDestroy {
@Input() groupId: string;
...
constructor( ) {
**this.groupID is always undefined**
}
Can it be this difficult ? Thanks!
Upvotes: 3
Views: 4517
Reputation: 33815
The issue is a matter of the angular 2 lifecyle, which occur in the following order, according to the "new" lifecycle hooks documentation and this older cheatsheet.
constructor
ngOnChanges
ngOnInit
ngDoCheck
ngAfterContentInit
ngAfterContentChecked
ngAfterViewInit
ngAfterViewChecked
ngOnDestroy
The constructor will always be called BEFORE inputs are available. If you attempt to access an input property from the constructor, the value will always be undefined.
The first time that input properties are processed is during ngOnChanges
and you could move your logic there, although the content of the template and the child views will not have been processed yet. However, the issue here is that it will be called every time the input properties change, which may be undesirable if you want to set once.
ngOnChanges() {
console.log(this.groupId);
}
A common solution to this problem is to move input-dependent logic to ngOnInit
, since it is called after input properties are initialized and after ngOnChanges
has run.
ngOnInit() {
console.log(this.groupId);
}
Once you move the check for this.groupId
to ngOnInit
, the input property will be properly hydrated.
See this plunker. The constructor will always return undefined
and the ngOnInit hook properly returns 6
.
In regards to the discussion in the comments, I want to modify my original understanding. Input properties ARE indeed available before the content is rendered, since that happens after ngOnInit
and before ngAfterContentInit
, per the cheatsheet and new lifecycle hooks documentation:
Called after ngOnInit when the component's or directive's content has been initialized.
Upvotes: 2
Reputation: 202156
You should use this:
template: `
<div class='another_page'></div>
<asset-manager groupId="6"></asset-manager>
<div class='another_page'></div>
`
or
template: `
<div class='another_page'></div>
<asset-manager [groupId]="'6'"></asset-manager>
<div class='another_page'></div>
`
With [...], you try to evaluate an expression. In your case, the expression is 6
but this doesn't correspond to something, so it's undefined.
Edit
Following the Mark's comment, the actual problem is that the values aren't available (undefined) in the constructor but will be in the ngOnInit
hook...
Upvotes: 1