Search code examples
angulardata-bindingnativescriptangular2-nativescript

Implementing radio button behavior using a switch in Nativescript (angular 2)


I'm trying to mimic radio button behavior in nativescript but am having issues with the binding. The code below almost works but if I "long tap" or kinda swipe one of the switches I don't believe the binding works, because it then doesn't deselect when I tap another switch.

<StackLayout orientation="horizontal" *ngFor="let site of sites">
    <Label [text]="site.station_name" class="medium-spacing" (tap)="goToObserve()"></Label>
    <Switch text="" [checked]="isSiteSelected(site)" (tap)="toggleSite(site)"></Switch>
</StackLayout>

Here is the component function

toggleSite(site) {
    setTimeout(() => {
        for(var s of this.sites) {
            if(s.station_id == site.station_id) {
                s.selected = true;
            }
            else {
                s.selected = false;
            }
        }
    }, 50);
}

Any ideas on a correct implementation? I've tried various iterations using [ngModel], and (propertyChange)="toggleSite(site)" but nothing seems to work. Also the setTimeout seems hacky, but without it the switch seemed like it was always one behind the toggle.

Solution I'm using based on @Nikolay Tsonev answer. I'm happy I could get rid of the setTimeout. It's probably incorrect that I pass both parameters to toggleSite($event, site) but it seems to work.

<StackLayout orientation="vertical">
  <StackLayout orientation="vertical" class="data-grid">
    <StackLayout class="grid-header" orientation="horizontal">
      <Label text="Sites" class="left-column" width="70%"></Label>
      <Label text="Selected" class="right-column" width="30%"></Label>
    </StackLayout>
    <ScrollView height="50%">
      <StackLayout>
        <StackLayout orientation="horizontal" *ngFor="let site of sites" height="50">
          <Label text="{{ cameraIcon }}" (tap)="viewSitePhoto()" class="icon" width="10%"></Label>
          <Label [text]="site.station_name" class="medium-spacing" (tap)="viewSiteObservations()" width="60%" text-align="left"></Label>
          <Switch text="" [checked]="site.selected" (checkedChange)="toggleSite($event, site)" width="30%" text-align="right"></Switch>
            </StackLayout>
        </StackLayout>
    </ScrollView>
  </StackLayout>
</StackLayout>

and inside my component I have:

toggleSite(event, site) {
    let newSwitchValue = event.value;
    if(newSwitchValue) {
        for(var s of this.sites) {
            if(s.station_id == site.station_id) {
                s.selected = true;
            }
            else {
                s.selected = false;
            }
        }
    }
}

Solution

  • You could use Switch checkedChange event, which will notify you when the value of the component has been changed. I am attaching sample code. For further help you could review those example - examples.

    app.component.html

    <StackLayout orientation="horizontal" >
        <Label text="station_name" class="medium-spacing"></Label>
        <Switch  checked="isSiteSelected" (checkedChange)="selectedvalueChanged($event)"></Switch>
    </StackLayout>
    

    app.component.ts

    import {Component} from "@angular/core";
    
    @Component({
        selector: "my-app",
        templateUrl: "app.component.html",
    })
    export class AppComponent {
        public counter: number = 16;
    
        public get message(): string {
            if (this.counter > 0) {
                return this.counter + " taps left";
            } else {
                return "Hoorraaay! \nYou are ready to start building!";
            }
        }
    
        public onTap() {
            this.counter--;
        }
         public selectedvalueChanged(args) {
             console.log(args.object.checked)
    
    }
    }