Reputation: 2650
I am attempting to create a component that allows the user to select actions to be performed on "tests" using a table interface. Each row of the table is a separate child component with the parent component comprising of the table headers and the child component rows, which are created using *ngFor
.
Everything is mostly going well, except I need the checkbox in the header to check all of the child component checkboxes and the select in the header to select all of the child component to equal the chosen option in the header. The checkboxes look like it works (as demoed in the Plunker), but the event handler in the parent component does not get the updated checked value when the header checkbox is checked, but does when the actual row's checkbox is checked. The demo has the checkboxes printing stuff to the console. I would expect the header checkbox to trigger all of the checkbox's 'checked' event and print multiple statements to the console (two lines per table row).
I started putting the pieces in place to handle the header's select changing, but am a little stuck as to how to make a select's option selected when the options are being populated using *ngFor
.
I don't know if it matters, but I am using angular2-beta 15 and am trying to stay on this version if possible.
Plunker and code dump are below.
import {Component, EventEmitter, Output, Input} from 'angular2/core'
// Child Component
@Component({
selector: 'tbody',
template: `
<td>{{ test }}</td>
<td>
<select (change)="selectedActionChange($event)">
<option *ngFor="#opt of optionList">{{ opt }}</option>
</select>
</td>
<td class="center">
<input type="checkbox" [ngModel]="checkboxValue" (ngModelChange)="checkboxChanged($event)" />
</td>
`
})
export class ChildComponent {
@Input() test: string;
@Input() checkboxValue: boolean;
@Input() selectedAction: string;
@Output() action: EventEmitter<any> = new EventEmitter();
@Output() checked: EventEmitter<any> = new EventEmitter();
optionList: Array<string> = ["Add", "Replace", "Skip"];
selectedActionChange(event) {
this.action.emit({
value: event.srcElement.value,
test: this.test
});
}
checkboxChanged(event: any) {
this.checked.emit({
value: event,
test: this.test
});
}
}
// Parent Component
@Component({
selector: 'parent',
template: `
<table>
<thead>
<tr>
<th>Test Name</th>
<th>
<label>Action</label>
<br />
<select (change)="headerSelectChanged($event)">
<option *ngFor="#opt of optionList">{{ opt }}</option>
</select>
</th>
<th>
<label>Import Test</label>
<br />
<input type="checkbox" checked (change)="headerCheckboxChanged($event)"/>
</th>
</tr>
</thead>
<tbody *ngFor="#test of testList" [test]="test" [checkboxValue]="masterCheckboxValue" [selectedAction]="masterSelectAction"
(action)="actionChange($event)" (checked)="checkedChanged($event)"></tbody>
</table>
`,
directives: [ChildComponent]
})
export class ParentComponent {
testList: Array<string> = ["Test 1", "Test 2", "Test 3"];
optionList: Array<string> = ["Add", "Replace", "Skip"];
masterCheckboxValue: boolean = true;
masterSelectAction: string;
headerCheckboxChanged(event: any): void {
this.masterCheckboxValue = event.srcElement.checked;
}
headerSelectChanged(event: any): void {
this.masterSelectAction = event.srcElement.value;
}
actionChange(event: any) {
console.log(event.test);
console.log(event.value);
}
checkedChanged(event: any) {
console.log(event.test);
console.log(event.value);
}
}
Upvotes: 0
Views: 1422
Reputation: 1665
It is not the problem of *ngFor
, but the problem of preventing any loops in parent<->child communication.
I checked - this will help you:
Add this code to your child component and try
ngOnChanges(changes: SimpleChanges) {
if (changes.checkboxValue) {
this.checked.emit({
value: changes.checkboxValue.currentValue,
test: this.test
});
}
if (changes.selectedAction) {
...
}
}
Maybe you will have to import and add implements onChanges
class, but it is not mandatory
Upvotes: 1