Reputation: 3847
I am trying to switch a set of radio buttons with angular class and attribute statements. When I click the buttons I can see the active
class being added and removed as required and the checked
attribute being set too. However the radio button doesn't actually get checked.
<div class="btn-group " data-toggle="buttons">
<label class="btn btn-primary" [ngClass]="{'active': s}">
<input type="radio" name="options" id="option1" autocomplete="off" (click)="s=true" [attr.checked]="s"> Yes
</label>
<label class="btn btn-primary" [ngClass]="{'active': !s}">
<input type="radio" name="options" id="option2" autocomplete="off"(click)="s=false" [attr.checked]="!s"> No
</label>
</div>
Using Angular 5, bootstrap 4.0.0
EDIT: Not a duplicate because I know there are other ways of doing it. But I am trying to figure out why the above method isn't working.
EDIT2: If I bind to a function with (click)="doSomething()"
it works! but also causes an error because the function isn't defined. If I create the function it stops working again.
Upvotes: 3
Views: 4500
Reputation: 2147
I have a better solution. You might appreciate the simplicity. Because the user is actually going to click the radio button, they had it with ngmodel which passes data into field, which you don't want.
html
<div class="btn-group" role="group" aria-label="View Type">
<button type="button" [class.active]="sortClass" (click)="switch(1)" class="btn btn-secondary">
<span>Grid</span>
</button>
<button type="button" [class.active]="listClass" (click)="switch(2)" class="btn btn-secondary">
<span>List</span>
</button>
</div>
component.ts
// Create variables
private sortClass: boolean;
private listClass: boolean;
// INITIALIZE TRUE / FALSE for both variables
constructor() {
this.sortClass = false;
this.listClass = true;
}
switch(i) {
if (i === 1) {
this.sortClass = !this.sortClass
this.listClass = !this.listClass
} else {
this.listClass = !this.listClass
this.sortClass = !this.sortClass
}
}
Then you will see one active, and the other false. When you click they will alternative true/false.
Upvotes: 2
Reputation: 73731
Strange things happen when processing the click
event. If the flag value is set directly in the template, the radio buttons are not checked correctly:
(click)="s = false"
but if the flag is set with a method, then everything works well:
(click)="setValue(false)"
You may prefer to handle the change
event, which seems to work correctly all the time:
(change)="s = false"
A better alternative is to use data binding with ngModel
, as shown in this stackblitz:
<div class="btn-group" data-toggle="buttons">
<label class="btn btn-primary" [class.active]="s">
<input type="radio" name="options" id="option1" [(ngModel)]="s" [value]="true"> Yes
</label>
<label class="btn btn-primary" [class.active]="!s">
<input type="radio" name="options" id="option2" [(ngModel)]="s" [value]="false"> No
</label>
</div>
Upvotes: 1
Reputation: 458
changing the attribute must be happening outside of Angular's context so you need to NgZone.run()
https://angular.io/api/core/NgZone
blah() {
this.zone.run(() => { console.log("boom!"); });
}
<div class="btn-group " data-toggle="buttons">
<label class="btn btn-primary" [ngClass]="{'active': s}">
<input type="radio" name="options" id="option1" autocomplete="off" (click)="s=true; blah();" [attr.checked]="s === 'true' ? true : false"> Yes
</label>
<label class="btn btn-primary" [ngClass]="{'active': !s}">
<input type="radio" name="options" id="option2" autocomplete="off"(click)="s=false; blah();" [attr.checked]="s === 'false' ? true : false"> No
</label>
</div>
Upvotes: 0