Reputation: 4217
I can think of a few ways that I might hack this but I'd like some advice on the most 'Angular' way of doing it.
I've put together an example of what I'm doing.
The main component uses NgFor
to iterate over a list and create a bunch of child components.
Each child emits an event when clicked which is picked up by the parent. Each child also has a method update()
.
What I want is the correct way for my main component to get a reference to to whichever child emits an event and call its update()
method.
Seems pretty simple (probably is pretty simple) but it is quite a central feature of the app I'm building so I want to do it as nice and clean as possible.
Cheers for you help
Upvotes: 5
Views: 3095
Reputation: 4602
Since Angular 2 embraced the one-way data flow paradigm, I would argue that the "most 'Angular' way" to solve this problem is to not call the update()
method at all. The state of child components should be provided by the parent.
Whenever the click happens, the new state should be computed in the App
(parent) component and will be passed down to the ChildComponent
.
Going this way, you will need to extend the state that is held in the parent, by an additional property (eg. clicked
):
rowList = [{name: "Alice", clicked: false}, ...];
(Of course, since undefined
has the same logical value as false
, explicit declaration is not really necessary.)
On click, in the handler method, the new state is computed. In this case, it's just a simple boolean value change:
processClick(id){
this.recentClick = id;
// Create the new array for immutability benefits.
this.rowList = this.rowList.map(person => {
if (person.name === id) {
return {name: person.name, clicked: true};
} else {
return person;
}
})
}
The value is passed down to the child, as any other @Input
.
<my-child *ngFor="let row of rowList;" [id]=row.name [clicked]=row.clicked (onMD)="processClick($event)"></my-child>
Now, the child component can change it's behavior depending on the value of the clicked
property. As a bonus, when using immutable data, you can change the change detection strategy to onPush
for some performance benefits.
@Component({
// ...
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent {
@Input() clicked: boolean;
get prefix() {
return this.clicked ? "Bye!" : "Hi";
}
// ...
}
There are multiple benefits of this approach.
update()
behavior works.The full implementation would look like this: http://plnkr.co/edit/IP8iLKxKGCjHOdgPHJ0h?p=preview
Upvotes: 4
Reputation: 691943
The simplest way is to use a template variable to reference the child component:
<my-child #child *ngFor="let row of rowList;" [id]="row.name"
(onMD)="processClick($event); child.update()"></my-child>
Updated demo: http://plnkr.co/edit/zA80iNsLHHULGx9Rbffw?p=preview
Upvotes: 5