frontend/src/app/spot/components/toggle/toggle.component.ts
import {
ChangeDetectorRef,
ChangeDetectionStrategy,
Component,
EventEmitter,
forwardRef,
HostBinding,
Input,
Output,
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
export interface SpotToggleOption<T> {
value:T;
title:string;
};
@Component({
selector: 'spot-toggle',
templateUrl: './toggle.component.html',
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SpotToggleComponent),
multi: true,
}],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SpotToggleComponent<T> implements ControlValueAccessor {
// TODO: These old styles will need to be replaced
@HostBinding('class.form--field-inline-buttons-container') public classNameOld = true;
@HostBinding('class.spot-toggle') public className = true;
/**
* The array of options that should be shown. Options have a simple structure:
*
* ```
* {
* title:string;
* value:T;
* }
* ```
*
* `title` will be shown in the toggle for the user to read, while `value` will be the
* value that is set as the ngModel if the option is selected.
*/
@Input() options:SpotToggleOption<T>[] = [];
/**
* Whether the input should be disabled
*/
@Input() disabled = false;
/**
* The name of the input. Will be autogenerated if not given,
* but especially useful to provide in a hybrid Rails <-> Angular context
* where a submit of a form is handled without JS.
*/
@Input() name = `spot-toggle-${+(new Date())}`;
/**
* If you're not using Angular Reactive Forms (Which you should be using!)
* then you can manually set the value via this input.
*/
@Input() public value:T;
/**
* Emits when the selected value changes.
*/
@Output() valueChange = new EventEmitter<T>();
constructor(
private cdRef:ChangeDetectorRef,
) {}
writeValue(value:T):void {
this.value = value;
this.cdRef.markForCheck();
}
onToggle(value:T):void {
this.writeValue(value);
this.onChange(value);
this.onTouched(value);
}
onChange = (_:T):void => {};
onTouched: (t:T) => void = (_:T):void => {};
registerOnChange(fn:(_:T) => void):void {
this.onChange = fn;
}
registerOnTouched(fn:(_:T) => void):void {
this.onTouched = fn;
}
}