Ashkar Km
Ashkar Km

Reputation: 138

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!

Upvotes: 6

Views: 2896

Answers (2)

Pankaj Parkar
Pankaj Parkar

Reputation: 136124

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

Upvotes: 7

Robby Cornelissen
Robby Cornelissen

Reputation: 97120

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.

Upvotes: 6

Related Questions