All files / src/app/shared/components/time-input time-input.component.ts

83.78% Statements 31/37
100% Branches 10/10
58.33% Functions 7/12
88.23% Lines 30/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 905x 5x 5x                                   5x               7x 5x       1x             7x     7x               1x 1x 1x       5x 4x 1x 4x 1x 4x   1x           4x 4x 4x       3x 1x 2x 2x       1x 1x 1x   7x    
import { CommonModule } from "@angular/common";
import { ChangeDetectorRef, Component, Input, OnChanges, OnInit } from "@angular/core";
import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from "@angular/forms";
 
@Component({
    selector: "app-time-input",
    standalone: true,
    imports: [
        CommonModule,
        FormsModule,
    ],
    providers: [
        {
            provide: NG_VALUE_ACCESSOR,
            useExisting: TimeInputComponent,
            multi: true,
        },
    ],
    templateUrl: "./time-input.component.html",
})
export class TimeInputComponent implements OnInit, OnChanges, ControlValueAccessor {
    @Input() min: number | undefined;
    @Input() max: number | undefined;
    @Input() label: string | undefined;
    @Input() id: string | undefined;
    @Input() valid?: boolean;
    
    value: number | undefined;
    disabled = false;
    static instanceCount = 0;
 
    // Reactive Form (instead of Model Binding)
    writeValue (value: number) {this.value = value; this.updateValue();};
    registerOnChange (fn: (value: number | undefined) => void) {this.onChangeCallback = fn;}
    registerOnTouched (fn: () => void) {this.onTouchedCallback = fn;}
    setDisabledState (disabled: boolean) {this.disabled = disabled;}
 
    onChangeCallback: ((value: number | undefined) => void) | undefined;
    onTouchedCallback: (() => void) | undefined;
 
    stringTime = "0:0";
 
    //Constructor
    constructor (private readonly cdr: ChangeDetectorRef) {}
 
    // Lifecycle Hooks
    ngOnChanges () {
        this.updateValue();
    }
 
    ngOnInit () {
        if(!this.id)
            this.id = "timeinput-" + TimeInputComponent.instanceCount++;
        this.updateValue();
    }
 
    updateValue () {
        if(this.value){
            if(this.max && this.value > this.max)
                this.value = this.max;
            if(this.min && this.value < this.min)
                this.value = this.min;
            this.stringTime = this.getStringTime(this.value);
        } else {
            this.stringTime = "0:0";
        }
    }
 
    // UI Methods
    getStringTime (time: number): string {
        const hours = String(Math.floor(time / 60)).padStart(2, "0");
        const minutes = String(time % 60).padStart(2, "0"); 
        return `${hours}:${minutes}`;
    }
 
    getTime (input: string) {
        if(!input)
            return undefined;
        const [hours, minutes] = input.split(":").map(Number);
        return hours * 60 + minutes;
    }
 
    onChange () {
        this.value = this.getTime(this.stringTime);
        this.updateValue();
        this.onChangeCallback?.(this.value);
    };
    detectChanges = () => this.cdr.detectChanges();
}