Reputation: 233
I have a very weird problem (never saw before) with my component. I'm trying to remove a line when clicking on a button inside a ngFor list. When I have only one line it works but when It's more than one line the event is fired twice, once for the good line and once for the first line (after deleted the other line) :
<label>
<div class="tag" *ngFor="let o of selectedOptions;">
<span class="tag-text">{{ o.textContent }}</span>
<button (click)="removeTag(o)" type="button" class="fa fa-times"></button>
</div>
</label>
And here is my method witch is called twice (only if there is more that one "option") :
public removeTag (option: NxtSelectOptionComponent) {
this.selectedOptions = [
...this.selectedOptions.filter(o => o !== option),
]
}
I've tried to use splice, I've tried to add stopPropagation... I don't understand I've done it tons of time and this is the first time I see that.
EDIT : the removeTag method is called when I click on .tag
element this is why when I click on the button it is called twice, but I can't figure this out why... the (click)
attribute is only on the button
Problem resolved : I've found the problem... FYI label tag will click on the button so if you have any (click) attribute it'll fired twice.
Upvotes: 11
Views: 10143
Reputation: 139
Worth mentioning my situation in case it is tripping anyone else up. The component which housed the buttons was subscribed to an observable and never unsubscribed so this was keeping old components alive and firing their click methods. Make sure to .unsubscribe() any subscriptions you create in the button's parent component.
Upvotes: 3
Reputation: 3188
Full solution:
<label>
<div class="tag" *ngFor="let o of selectedOptions;">
<span class="tag-text">{{ o.textContent }}</span>
<button (click)="removeTag(o, $event)" type="button" class="fa fa-times"></button>
</div>
</label>
Then the method that takes the event:
public removeTag (option: NxtSelectOptionComponent, event) {
event.preventDefault(); // This is needed to prevent the click event from firing twice on a label
this.selectedOptions = [
...this.selectedOptions.filter(o => o !== option),
]
}
Upvotes: 2
Reputation: 470
Actually the second click will be called by the parent element. The browsers default behavior is, to trigger a click on the input, once the parent got clicked.
Use
event.preventDefault();
to stop second trigger.
Upvotes: 11
Reputation: 2494
Try this
<div *ngFor="let user of users; let i=index" >
{{user.name}}
<div>
<a class="btn btn-danger" (click)="removeUser(i)">-</a>
</div>
</div>
removeUser(i): void {
this.users.splice(i, 1);
}
Upvotes: 0