Reputation: 967
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.
this.serverData = [
{
'name': 'None',
'value': 1,
'isSelected': true
},
{
'name': 'Debug',
'value': 2,
'isSelected': false
},
{
'name': 'Error',
'value': 3,
'isSelected': false
}
];
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;
}
}
}
}
<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
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]
}
Upvotes: 1
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
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
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
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