3

I have a @Input property in my child component of type Person and I'm passing the object from the parent component through an attribute

Full working code is available in StackBlitz

I explored the following question I got the point that what they told in the answer but I tried the Object.assign and other things based on the answer but it fails to load the data in View.

How can I pass the Object through @Input and how can I do some manipulation once the object reached to the child component and need to update in the view?

Sample Code:

App Component:

import { Component } from '@angular/core';

import { Person } from './models/person'

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  person: Person = {
    firstName: 'Emma',
    lastName: 'Watson'
  };
}

App Component HTML:

<user [user-profile]="person"></user>

User Component:

import { Component, OnInit, Input, OnChanges, SimpleChanges } from '@angular/core';
import { Person } from '../models/person';

@Component({
  selector: 'user',
  templateUrl: './user.component.html',
  styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit, OnChanges {

  @Input('user-profile') profile: Person;

  person: Person;

  constructor() {}

  ngOnInit() { 
    this.person = {
      firstName: '',
      lastName: ''
    }
  }

  ngOnChanges(changes:SimpleChanges): void { 
    if(typeof this.profile !== 'undefined' 
      && typeof this.profile.firstName !== 'undefined' 
      && typeof this.profile.lastName !== 'undefined') {
        this.person.firstName = this.profile.firstName;
        this.person.lastName = this.profile.lastName;
    }
  }

}

User Component HTML:

Full Name: {{person.firstName}} {{person.lastName}}

I need to do some manipulation once I received the object from @Input and need to update it in the UI. I know the object is passing as reference but here I tried with Object.assign and I assigned the property with undefined and then the appropriate object nothing is working.

user11281949
  • 105
  • 6
B.Balamanigandan
  • 4,713
  • 11
  • 68
  • 130

2 Answers2

4

Remove the asignment of person from ngOnInit(), ngOnInit runs after ngOnChanges so you are restting the values back to empty

export class UserComponent implements OnInit, OnChanges {

  @Input('user-profile') profile: Person;

  person: Person = { firstName: '', lastName: '' };  // initialize it here

  constructor() {}

  ngOnInit() { 
    // this.person = {
    //   firstName: '',
    //   lastName: ''
    // }
  }

  ngOnChanges(changes:SimpleChanges): void { 



    if(typeof this.profile !== 'undefined' 
      && typeof this.profile.firstName !== 'undefined' 
      && typeof this.profile.lastName !== 'undefined') {
        console.log(this.profile)
        this.person.firstName = this.profile.firstName;
        this.person.lastName = this.profile.lastName;
        console.log(this.person)
    }
  }

}

https://stackblitz.com/edit/angular-input-ng-onchange-qiyghn?file=src%2Fapp%2Fuser%2Fuser.component.ts

Ashish Ranjan
  • 12,760
  • 5
  • 27
  • 51
2

It's because ngOnInit is ran after ngOnChanges. So you first set it, but then immediately reset it inside your ngOnInit.

See here a working example.

Basically change your component person attribute to this:

person: Person = {
  firstName: '',
  lastName: ''
};

and remove the ngOnInit.

You can also use a setter on the profile input, this way you don't need ngOnChanges:

@Input('user-profile') set profile(person: Person) {
  this.person.firstName = profile && profile.firstName || '';
  this.person.lastName = profile && profile.lastName || '';
}

person: Person = {
  firstName: '',
  lastName: ''
};
Poul Kruijt
  • 69,713
  • 12
  • 145
  • 149
  • Shall I do the initial assignment in the constructor ? – B.Balamanigandan Apr 03 '19 at 12:45
  • @B.Balamanigandan personally I think it's neater to do it on the property itself, but it doesn't really matter, the functionality will be the same. In Angular it's common to keep the constructor as empty as possible, and just use it for dependency injection – Poul Kruijt Apr 03 '19 at 12:49
  • Don't mistake me. I marked based of FIFO. I up-voted very first for you answer. – B.Balamanigandan Apr 03 '19 at 13:35
  • 1
    @B.Balamanigandan No worries :) I understand your reasoning. I actually did answer first, but edited within the minute, which made the edit merge with original answer, and updated the timestamp to after the other answer. But xyz deserves it more, he needs to points! – Poul Kruijt Apr 03 '19 at 14:31