Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Angular 2 Two and Tri state slide toggle component,
<ng-container [ngSwitch]="triState">
<ng-container *ngSwitchCase="true">
<input type="radio" id="mf" class="trigger mf" [value]="false" [(ngModel)]="model" (change)="update(model)" [disabled]="isDisabled">
<label for="mf"></label>
<input id="st_{{formControlName}}_off" [name]="formControlName" type="radio" class="trigger minus" [value]="-1" [(ngModel)]="model" (change)="update(model)" [disabled]="isDisabled">
<label for="st_{{formControlName}}_off">
<div class="pin">
<div class="ink"></div>
</div>
</label>
<input id="st_{{formControlName}}_on" [name]="formControlName" type="radio" class="trigger plus" [value]="1" [(ngModel)]="model" (change)="update(model)" [disabled]="isDisabled">
<label for="st_{{formControlName}}_on">
<div class="pin">
<div class="ink"></div>
</div>
</label>
</ng-container>
<ng-container *ngSwitchDefault>
<input id="st_{{formControlName}}" [name]="formControlName" type="checkbox" class="trigger" [(ngModel)]="model" (change)="update(model)" [disabled]="isDisabled">
<label for="st_{{formControlName}}">
<div class="pin">
<div class="ink"></div>
</div>
</label>
</ng-container>
</ng-container>
@import '~compass-mixins/lib/compass';
@import '~compass-mixins/lib/animation/core';
@import 'base/variables';
@import 'base/mixins';
$slide-spacing: 3px;
$slide-width: 34px;
$slide-height: ($slide-width / 2) + 1;
input.trigger {
&:focus {
+ label {
.pin {
background-color: darken($main-color, 10%);
}
}
}
&:active {
+ label {
.ink {
@include animation-play-state(running);
}
}
}
&:checked {
+ label {
background-color: $main-color;
.ink {
@include animation-name(slide-ripple-checked);
@include animation-play-state(unset);
}
.pin {
background-color: $white;
left: calc(100% - #{$slide-height - $slide-spacing});
}
}
}
&[disabled] {
+ label {
border-color: $light-grey;
cursor: not-allowed;
.pin {
background-color: $light-grey;
}
}
}
}
label {
@include border-radius(50%, $slide-height);
@include transition(background-color .3s ease-in-out);
@include inline-block;
border: 1px solid $medium-grey;
height: $slide-height;
margin: 0 6px;
position: relative;
width: $slide-width;
.pin {
@include circle($slide-height - $slide-spacing * 2);
@include transition(left .3s .2s ease-in-out);
background-color: $main-color;
content: '';
left: $slide-spacing;
position: absolute;
top: $slide-spacing - 1px;
}
.ink {
@include animation(slide-ripple-unchecked .5s .2s linear paused);
@include border-radius(50%);
@include transform(scale(0));
background: rgba($main-color, .5);
height: 100%;
position: absolute;
width: 100%;
}
}
:host {
@include inline-block(middle);
&.tri-state {
@include flexbox((display: flex));
margin-left: 18px;
position: relative;
label {
@include border-radius(0 50% 50% 0, $slide-height);
border-left: none;
margin: 0;
position: relative;
}
input.trigger {
&.mf {
+ label {
@include border-radius(0);
background-color: transparent;
border: none;
height: 16px;
left: 0;
position: absolute;
top: 1px;
width: 16px;
z-index: 2;
}
&:checked {
+ label {
background-color: transparent;
}
~ label {
.pin {
@include transition(background-color .2s .1s ease-in-out);
}
}
}
}
&.minus,
&.plus {
+ label {
margin-left: -18px;
}
}
&.minus {
+ label {
@include rotate(180deg);
}
&:checked {
~ .plus + label {
background-color: $main-color;
}
}
}
}
&.on {
label {
background-color: $main-color;
}
.minus,
.plus {
&:checked {
+ label {
z-index: 1;
}
}
}
}
}
}
import { Component, forwardRef, HostBinding, Input } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'slide-toggle',
templateUrl: './slide-toggle.component.html',
styleUrls: ['./slide-toggle.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SlideToggleComponent),
multi: true
}
]
})
export class SlideToggleComponent implements ControlValueAccessor {
@Input()
formControlName: string;
@HostBinding('class.tri-state')
@Input()
triState: boolean;
@HostBinding('class.on')
model: boolean;
isDisabled: boolean;
constructor() {
}
update(model: boolean) {
this.onTouched();
this.propagateChange(model);
}
onTouched() {
}
writeValue(model: any): void {
this.model = model || false;
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean): void {
this.isDisabled = isDisabled;
}
private propagateChange(_model: boolean) {
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment