All files / select/selection si-select-selection-strategy.ts

100% Statements 22/22
100% Branches 2/2
91.66% Functions 11/12
100% Lines 20/20

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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110                                                            1x             137x           130x       137x                       137x 58x             137x   141x 137x 137x 137x     44x       44x               16x 16x 16x 16x       31x       51x               181x      
/**
 * Copyright (c) Siemens 2016 - 2025
 * SPDX-License-Identifier: MIT
 */
import {
  booleanAttribute,
  computed,
  Directive,
  inject,
  input,
  Input,
  output,
  signal,
  Signal
} from '@angular/core';
import { ControlValueAccessor } from '@angular/forms';
 
import {
  SI_SELECT_OPTIONS_STRATEGY,
  SiSelectOptionsStrategy
} from '../options/si-select-options-strategy';
 
/**
 * Selection strategy base class.
 */
@Directive({
  host: {
    '[class.disabled]': 'disabled()'
  }
})
export abstract class SiSelectSelectionStrategy<T, IV = T | T[]> implements ControlValueAccessor {
  /**
   * Whether the select input is disabled.
   *
   * @defaultValue false
   */
  // eslint-disable-next-line @angular-eslint/no-input-rename
  readonly disabledInput = input(false, { alias: 'disabled', transform: booleanAttribute });
 
  /**
   * The selected value(s).
   */
  @Input() set value(value: IV | undefined) {
    this.updateFromInput(this.toArrayValue(value));
  }
 
  /** Emitted when the selection is changed */
  readonly valueChange = output<IV>();
 
  /**
   * Whether the select control allows to select multiple values.
   * @internal
   */
  abstract readonly allowMultiple: boolean;
 
  /**
   * Provides the internal value always as an array
   * @internal
   */
  readonly arrayValue: Signal<readonly T[]> = computed(() =>
    this.selectOptions.selectedRows().map(option => option.value)
  );
 
  /**
   * Registered form callback which shall be called on blur.
   * @internal
   */
  onTouched: () => void = () => {};
  /** @internal */
  public readonly disabled = computed(() => this.disabledInput() || this.disabledNgControl());
  protected onChange: (_: any) => void = () => {};
  private readonly disabledNgControl = signal(false);
  private readonly selectOptions = inject<SiSelectOptionsStrategy<T>>(SI_SELECT_OPTIONS_STRATEGY);
 
  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }
 
  registerOnChange(fn: any): void {
    this.onChange = fn;
  }
 
  /**
   * CDK Listbox value changed handler.
   * @internal
   */
  updateFromUser(values: T[]): void {
    const parsedValue = this.fromArrayValue(values);
    this.onChange(parsedValue);
    this.valueChange.emit(parsedValue);
    this.selectOptions.onValueChange(values);
  }
 
  setDisabledState(isDisabled: boolean): void {
    this.disabledNgControl.set(isDisabled);
  }
 
  writeValue(obj: any): void {
    this.updateFromInput(this.toArrayValue(obj));
  }
 
  protected abstract toArrayValue(value: IV | undefined): readonly T[];
 
  protected abstract fromArrayValue(value: readonly T[]): IV;
 
  private updateFromInput(values: readonly T[]): void {
    this.selectOptions.onValueChange(values);
  }
}