@engie-group/fluid-design-system-angular
Version:
Fluid Design System Angular
222 lines (189 loc) • 4.91 kB
text/typescript
import {CommonModule} from '@angular/common';
import {
booleanAttribute,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ElementRef,
EventEmitter,
forwardRef,
Input,
Output,
ViewChild
} from '@angular/core';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
import {IconComponent} from '../icon/icon.component';
import {CheckboxSize} from './checkbox.model';
export class CheckboxComponent implements ControlValueAccessor {
private readonly checkboxClassName = 'nj-checkbox';
private _checked: boolean;
/**
* Input id
*/
inputId: string;
/**
* Input name
*/
name: string;
/**
* Whether input is required or not
*/
isRequired?: boolean;
/**
* Whether the checkbox is checked or not
*/
set isChecked(value: boolean) {
this._checked = value;
this.cdr.markForCheck();
}
get isChecked(): boolean {
return this._checked;
}
/**
* Checkbox size
*/
size?: CheckboxSize = 'md';
/**
* Input value
*/
value?: string;
/**
* Whether the checkbox is disabled or not
*/
isDisabled?: boolean;
/**
* Whether the checkbox is in error state
*/
hasError?: boolean;
/**
* Whether the checkbox is in success state
*/
hasSuccess?: boolean;
/**
* Message to display as hint below checkbox
*/
subscriptMessage?: string;
/**
* @Deprecated
* Message to display if checkbox is in error state
*/
errorMessage?: string;
/**
* Aria label, for accessibility reasons
*/
ariaLabel?: string;
/**
* Aria labelled by, for accessibility reasons
*/
ariaLabelledby?: string;
/**
* Whether checkbox is only presentational and state handled by a parent, can be useful for lists of checkboxes.
* When set to `true`, the checkbox won't have any interaction.
*/
isPresentational? = false;
/**
* Whether the checkbox is in indeterminate state or not.
*/
indeterminate: boolean;
/**
* Output that emits checked value on change only
*/
valueChange: EventEmitter<boolean> = new EventEmitter<boolean>();
private _inputElement: ElementRef<HTMLInputElement>;
constructor(private cdr: ChangeDetectorRef) {
}
/**
* @ignore
*/
private _onChange = (_: any): void => {
};
/**
* @ignore
*/
private _onTouched = (): void => {
};
/**
* @ignore
*/
_onChangeEvent(event: Event) {
event.stopPropagation();
if (this._inputElement?.nativeElement) {
this.isChecked = this._inputElement.nativeElement.checked;
this._onChange(this.isChecked);
this.valueChange.emit(this.isChecked);
}
}
/**
* @ignore
*/
_onInputClick(event: Event) {
// We have to stop propagation for click events on the visually hidden input element.
// By default, when a user clicks on a label element, a generated click event will be
// dispatched on the associated input element. Since we are using a label element as our
// root container, the click event on the `slide-toggle` will be executed twice.
// The real click event will bubble up, and the generated click event also tries to bubble up.
// This will lead to multiple click events.
// Preventing bubbling for the second event will solve that issue.
event.stopPropagation();
}
/**
* Implemented as part of ControlValueAccessor.
* @ignore
*/
writeValue(value: any): void {
this.isChecked = !!value;
}
/**
* Implemented as part of ControlValueAccessor.
* @ignore
*/
registerOnChange(fn: any): void {
this._onChange = fn;
}
/**
* Implemented as part of ControlValueAccessor.
* @ignore
*/
registerOnTouched(fn: any): void {
this._onTouched = fn;
}
/**
* Implemented as part of ControlValueAccessor.
* @ignore
*/
setDisabledState(isDisabled: boolean): void {
this.isDisabled = isDisabled;
this.cdr.markForCheck();
}
/**
* @ignore
*/
getSubscriptId(): string {
return `${this.inputId}-hint`;
}
private get checkboxSizeClass(): string {
return this.size !== 'md' ? `${this.checkboxClassName}--${this.size}` : '';
}
protected get checkboxClasses() {
return {
'nj-checkbox--error': this.hasError,
'nj-checkbox--success': this.hasSuccess,
[this.checkboxSizeClass]: true
};
}
}