Pranjal Successena
Pranjal Successena

Reputation: 967

Angular: Unable to reset value in child component second time using @Input

Having a child component to handle dropdown. Parent component has a reset button to reset the selection made by the user to 'None' in the dropdown (child-component).

Here is the link to the code.

app.component.html:

   <app-child [serverData]="serverData" [selectedInpValue]="selectedValue" (selectedComboBoxItemEvent)="getSelectedItem($event)"></app-child>
   <!-- reset button -->
   <button (click)="resetData()">Reset Selection</button>

2 @Input properties, serverData & selectedInpValue are sent to child component. serverData has the list for the dropdown and selectedInpValue holds the selected value. By default, 'None' is displayed.


server data

this.serverData = [
      {
        'name': 'None',
        'value': 1,
        'isSelected': true
      },
      {
        'name': 'Debug',
        'value': 2,
        'isSelected': false
      },
      {
        'name': 'Error',
        'value': 3,
        'isSelected': false
      }
    ];


child.component.ts

export class ChildComponent implements OnInit, OnChanges {
  selectedItem: any;

  @Input() serverData: any[];
  @Input() selectedInpValue: any;
  @Output() selectedComboBoxItemEvent = new EventEmitter();

  ngOnInit() {
    this.selectedItem = this.serverData.find(data => data.isSelected);
    console.clear();
    console.log('child on init: ', this.serverData);
  }

  ngOnChanges() {
    console.clear();
    console.log('child old selectedInpValue: ', this.selectedItem);
    this.selectedItem = this.selectedInpValue;
    console.log('child new selectedInpValue: ', this.selectedItem);
  }

  selectItem() {
    const index = this.serverData.findIndex(x => x.value === this.selectedItem.value);
    this.serverData[index].isSelected = true;
    for (const data of this.serverData) {
      if (data.value === this.selectedItem.value) {
        data.isSelected = true;
      } else {
        data.isSelected = false;
      }
    }
  }
}


child.component.html

<select (change)="selectItem()" [(ngModel)]="selectedItem">
  <option *ngFor="let listItem of serverData" [ngValue]="listItem">{{ listItem.name }}</option>
</select>

Issue:

First & second click of Reset Selection makes selectedInpValue as-

selectedInpValue = {
        'name': 'None',
        'value': 1,
        'isSelected': true
      }

Since, on the second click, the input property selectedInpValue holds the same value as on the first click, the ngOnChanges does not trigger and reset does not happen.

How do I solve this?

Upvotes: 1

Views: 3623

Answers (5)

Eliseo
Eliseo

Reputation: 57939

First, if you want to asign the value of selectedItem, the first who has a propertie of isSelected equal true, you should use a getter in input, not the ngOnInit

  selectedItem: any;
  _serverData:any[]
  @Input()
  set serverData(value)
  {
    this._serverData=value;
    this.selectedItem = this.serverData.find(data => data.isSelected);
  }
  get serverData()
  {
     return this._serverData
  }

Second to "change" an array you need create a copy, not change individual element. You think an array as a point of the memory, you change the content, but the position of memory is the same.

resetData() {
    this.serverData[0].isSelected = true;
    this.serverData=[...this.serverData]
  }

your forked stackblitz

Upvotes: 1

paras shah
paras shah

Reputation: 889

You need top add a simple change detection event at children component like below mentioned

ngOnChanges(changes: { [property: string]: SimpleChange }) {  

// Extract changes to the input property by its name    

let change: SimpleChange = changes['data'];  

// Whenever the data in the parent
changes, this method gets triggered. You    can act on the changes
here. You will have both the previous value and the    current value
here.  
}

for more detail you can check this answer.

How to emit an event from parent to child?

Upvotes: 1

Kostas Asargiotakis
Kostas Asargiotakis

Reputation: 144

The parent is not being informed when the child updates the data.The 1st time the parent sends the None option. Then the child updates the data. And after that, the parent sends again the None option which correctly remains the same as the previous input, so the ngOnChanges does not fire. So you can pass a third input (e.g. a boolean) which values is being updated on each Click on reset

Parent

updateChild:boolean = false;

resetData() {
    this.serverData[0].isSelected = true;
    this.selectedValue = this.serverData[0];
    this.updateChild = !this.updateChild;
}

<app-child [serverData]="serverData" [selectedInpValue]="selectedValue" [reset]="updateChild"
  (selectedComboBoxItemEvent)="getSelectedItem($event)" ></app-child>

<button (click)="resetData()">Reset Selection</button>

Child

 @Input() reset:any;

Upvotes: 0

Dhaval Patel
Dhaval Patel

Reputation: 7601

You need to change every time reference of it, like

this.selectedValue = Object.assign({}, this.selectedValue);

please check the working code here Demo

Upvotes: 0

Abhishek
Abhishek

Reputation: 1778

You can use set function. this function is call on every change of input. if you can update serverdata value some value reflect on child component

@Input() set serverData(value) {
  // do some task
}

Upvotes: 0

Related Questions