Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 4 component two way binding issue

I have an array:

const a = [apple,ball,cat]

I'm passing this to two components:

<app-header [appData]="data"  ></app-header>

<list-todo [appData]="data" [getData]="getData" [setData]="setData" ></list-todo>

In the appHeader component,

export class appHeader  {
  @Input('appData') data : any

  clear(){
    this.data = []
  }
}

performing the clear() function is not affecting the array in the listTodo component. Is there any way to solve that issue?

I also checked two way binding with attributes but nothing worked anymore!

like image 270
Ashkar Km Avatar asked Aug 10 '17 10:08

Ashkar Km


2 Answers

Input binding sends data to child component in unidirectional way, so when we modify child component data it doesn't flow up. Since you're assigning new blank array to this.appData in child component(it doesn't flow up). In this case you could consider changing your appData property binding to be two way binding. So that anything updates in child component will update the relative property in parent component, but yes it doesn't happen magically. You have to update the data manually ;)

To make the same thing working, you have to emit changed copy of object to parent component via Output binding like [(appData)]="data" (it uses EventEmitter to emit data to parent compoent).

AppComponent Template

 <app-header [appData]="data"  ></app-header>
<list-todo [(appData)]="data"></list-todo>

ListTodoComponent

@Component({
  selector: 'list-todo',
  template: `
     <ul>
      <li *ngFor="let item of appData">{{item}}</li>
     </ul>
     <button (click)="clear()">Clear</button>
  `
})
export class ListTodoComponent { 
  @Input() appData;
  @Output() appDataChange: EventEmitter<any> = new EventEmitter<any>();

  clear(){
    this.appData = [];
    //this emit is important to send data back to parent.
    //make sure you should have `Change` prefix to bounded value, like `appData` + `Change` = `appDataChange`, 
    //which ultimately saves few lines of code.
    this.appDataChange.emit(this.appData); 
  }
}

Demo Here

like image 92
Pankaj Parkar Avatar answered Nov 06 '22 05:11

Pankaj Parkar


By doing this.data = [], you're not emptying your array, but replacing it with a new instance. Your parent component and the other child component are still referring to the original instance, which results in the behavior you describe.

One solution is to empty the original array instead of replacing it:

clear() {
    this.data.length = 0;
}

In doing so, all components will keep referring to the same array instance, and its state will be correctly reflected.

like image 45
Robby Cornelissen Avatar answered Nov 06 '22 04:11

Robby Cornelissen