Pennywise83
Pennywise83

Reputation: 1784

Understanding how parent and child components handle an object

I'm wondering how angular handle an object shared between a parent and child component.

Let me show you a simple example: ParentComponent

@Component({
  selector: 'app-parent',
  template: `<app-children [(data)]="message"></app-children>
            <div>Parent: {{message}}</div>`,
})

export class ParentComponent implements OnInit {
  public message: string;

  ngOnInit() {
    this.message = 'Original message'
  }
}

Children Component

@Component({
  selector: 'app-children',
  template: `<div>Children: {{data}}</div> 
             <a (click)="changeMessage('Children message')">Click me!</a>`
})

export class ChildrenComponent {
  @Input() public data: string;
  changeMessage(message: string) {
    this.data = message;
  }
}

When I click on the "Click me!" link, i see only the Children message change, but not the parent one. Isn't it the same object?

Upvotes: 7

Views: 177

Answers (2)

Amir Arbabian
Amir Arbabian

Reputation: 3699

The answer is that it's not the same object, because you completely reassign it to the new one here:

changeMessage(message: string) {
  this.data = message;
}

If you want to see whether it changes in parent component when you change it in child component, you have to change it, not create a new one, for example:

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

@Component({
  selector: 'app-root',
  template: `<app-children [data]="data"></app-children>
            <div>Parent: {{data.message}}</div>`,
})

export class AppComponent {
  public data = { message: "" };

  ngOnInit() {
    this.data.message = 'Original message'
  }
}

@Component({
  selector: 'app-children',
  template: `<div>Children: {{data.message}}</div> 
             <a (click)="changeMessage('Children message')">Click me!</a>`
})

export class ChildComponent {
  @Input() public data: { message: string };
  changeMessage(message: string) {
    this.data.message = message;
  }
}

Demo on stackblitz. Here we pass an object (where message it's just a field) to child component, and we modify object inside the child component, and changes being reflected in both components. Despite the fact that it works, it's not recommended to change an object inside of child components, for these purposes it's better to use @Output + EventEmitters. Hope that helps.

Upvotes: 3

Lia
Lia

Reputation: 11982

consider you should emit the changed value from child and also your emitter name should be [your bind var name]+'Change' so it will work:

import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `<app-children [(data)]="message"></app-children>
            <div>Parent: {{message}}</div>`,
})

export class AppComponent {
  public message: string;

  ngOnInit() {
    this.message = 'Original message'
  }
}

@Component({
  selector: 'app-children',
  template: `<div>Children: {{data}}</div> 
             <a (click)="changeMessage('Children message')">Click me!</a>`
})

export class ChildComponent {
  @Input() public data: string;
  @Output() dataChange= new EventEmitter<string>();
  changeMessage(message: string) {
    this.data = message;
    this.dataChange.emit(this.data);
  }
}

check DEMO and creating custom two-way data bindings.

Upvotes: 4

Related Questions