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             138x           132x       138x                       138x 60x             138x   142x 138x 138x 138x     45x       45x               16x 16x 16x 16x       32x       53x               185x      
/**
 * Copyright (c) Siemens 2016 - 2026
 * 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);
  }
}