87

Trying to get the component's @Input value in constructor or ngOnInit. But it is coming as undefined all the time.

I updated the hero plunker with console.log to show the issue (beta angular). http://plnkr.co/edit/dseNM7OTFi1VNG2Z4Oj5?p=preview

export class HeroDetailComponent implements OnInit {
  constructor(){
    console.log('hero', this.hero)
  }
  public hero: Hero;
  
  ngOnInit() {
    console.log('hero', this.hero)
  }
}

What am I doing wrong here?

2
  • Hmm, I didn't realize that in the example we are not selecting immidatelly the Hero... I was happy that it is not working in the plunker either :) I checked it in plunker and it is working fine. However in my code it is not working but it is initialized... sorry for the wrong plunker. I will accept the answer however it doesnt solve my issue. Commented Dec 21, 2015 at 14:07
  • 1
    So the problem was that I have put camelCase property "inputProperty" in the @Input... instead of "input-property" ... strange didnt realize.. however in the API documentation is written like this. Commented Dec 21, 2015 at 14:54

5 Answers 5

137

The reason you're getting undefined in ngOnInit is because at the point where the component is initialised you haven't actually passed in a Hero object

<my-hero-detail [hero]="selectedHero"></my-hero-detail>

At this point selectedHero has no value in your AppComponent and doesn't until the click event on the list calls the onSelect method

Edit: Sorry realised I didn't actually offer a fix. If you add an ngIf to my-hero-detail

<my-hero-detail *ngIf="selectedHero" [hero]="selectedHero"></my-hero-detail>

you should this will delay the initialisation of the my-hero-detail component and you should see the console output. This wont however output again when the selected hero changes.

Sign up to request clarification or add additional context in comments.

Comments

48

This is because the heroes are loaded asynchronously, so when the view renders initially, the selected hero is undefined. But then after a selection is made, the hero is passed into the details view with a defined value.

You are basically just seeing the onInit call based on the original value (undefined).

If you want something similar to execute after each selection, you can modify it like this:

export class HeroDetailComponent implements AfterViewChecked {
  constructor(){
    console.log('hero', this.hero)
  }
  public hero: Hero;

  ngAfterViewChecked() {
    console.log('hero', this.hero)
  }
}

3 Comments

Yes, it should.
using angular5 . Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'. Current value: '[object Object]'.
@FaizMohamedHaneef that happens if you change a value in that function. Since angular has already checked all the variables for changes it gives you a warning if you change a value afterwards in debug mode (not in production, since angular doesn't check again like in debug). If you really need to change a value and you are sure you are handling it correctly, wrap it in a Timeout.
28

I encountered the same behavior when I've got undefined of Input property value in ngOnInit. The statement *ngIf="selectedHero" in html code was not satisfied me. Moreover, using AfterViewChecked from @THG's answer was not a good solution for me, because it calls periodically and also it causes the warning ExpressionChangedAfterItHasBeenCheckedError when I want to change some variable (I didn't want to use workaround setTimeout). This is my solution for kind of this issue:

export class MyComponent implements OnChanges {
    @Input() myVariable: any;

    ngOnChanges(changes: SimpleChanges) {
        if (changes['myVariable']) {
            let variableChange = changes['myVariable'];
            //do something with variableChange.currentValue
        }
    }
}

I hope it helps someone later.

3 Comments

The if statement and bracketed variable did not work in my case, instead I simply checked for another condition. But it worked!! Thank you
it's working properly. I don't know why hasn't he approved this.
This is right way to do. We have to use "ngOnChanges()" when an input/output binding value changes, so to catch incoming value from @Input binding use above method. Although params provided in above example are because ngOnChanges() method receives a SimpleChanges object of current and previous property values to utilize further.
0

@Barabas solution did not work in my case. I end up using this

export class HeroDetailComponent implements OnChanges {
    @Input() hero: any;

    ngOnChanges(changes: SimpleChanges){
        if(changes.hero && changes.hero.currentValue){
            let currentHero = changes.hero.currentValue;
            //use currentHero
        }
    }
}

Comments

-1

In the ngOninit method use,

ngOnInit() {
    if(this.hero) 
        console.log('hero', this.hero);
}

2 Comments

Can someone explain why this was downvoted? It got rid of this error in my unit test.
The question was to not to skip the error but find a way to fix the error

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.