All files / select/options si-select-complex-options.directive.ts

100% Statements 23/23
100% Branches 12/12
100% Functions 8/8
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 111 112 113 114 115 116 117 118 119 120 121                                                        1x         33x                   33x                   76x               33x                   33x                   407x   33x 39x 39x 29x 10x 8x 8x   9x               2x         39x       38x 38x 407x                    
/**
 * Copyright (c) Siemens 2016 - 2025
 * SPDX-License-Identifier: MIT
 */
import { computed, Directive, input, OnChanges } from '@angular/core';
import { buildTrackByIdentity } from '@siemens/element-ng/common';
 
import { SelectGroup, SelectOption } from '../si-select.types';
import { SI_SELECT_OPTIONS_STRATEGY } from './si-select-options-strategy';
import { SiSelectOptionsStrategyBase } from './si-select-options-strategy.base';
 
/**
 * The directive allows passing custom options.
 * Otherwise, use the {@link SiSelectSimpleOptionsDirective} directive.
 *
 * @deprecated Use {@link SiSelectSimpleOptionsDirective} instead.
 *
 * @example
 * ```html
 * <si-select [complexOptions]="['v1', 'v2', 'v3']"></si-select>
 * <si-select [complexOptions]="{ g1: ['g1.i1', 'g1.i2'], g2: ['g2.i1']}"></si-select>
 * ```
 */
@Directive({
  // eslint-disable-next-line @angular-eslint/directive-selector
  selector: 'si-select[complexOptions]',
  providers: [{ provide: SI_SELECT_OPTIONS_STRATEGY, useExisting: SiSelectComplexOptionsDirective }]
})
export class SiSelectComplexOptionsDirective<T>
  extends SiSelectOptionsStrategyBase<T>
  implements OnChanges
{
  /** Options to be shown in select dropdown. */
  readonly complexOptions = input<T[] | Record<string, T[]> | null>();
 
  /**
   * @deprecated Property has no effect and can be removed.
   *
   * @defaultValue
   * ```
   * buildTrackByIdentity<T>()
   * ```
   */
  readonly trackBy = input(buildTrackByIdentity<T>());
 
  /**
   * By default, values are check on equality by reference. Override to customize the behavior.
   *
   * @defaultValue
   * ```
   * (a: T, b: T): boolean => a === b
   * ```
   */
  override readonly optionsEqual = input((a: T, b: T): boolean => a === b, {
    // eslint-disable-next-line @angular-eslint/no-input-rename
    alias: 'optionEqualCheckFn'
  });
 
  /**
   * The valueProvider is used to extract the display text of a value.
   */
  readonly valueProvider = input<(dropdownOption: T) => string | undefined>();
 
  /**
   * Provides Value for the display text of the dropdown group
   *
   * @defaultValue
   * ```
   * () => undefined
   * ```
   */
  readonly groupProvider = input<(groupKey: string) => string | undefined>(() => undefined);
 
  /**
   * The disabledProvider is used to display menu items as disabled.
   *
   * @defaultValue
   * ```
   * () => false
   * ```
   */
  readonly disabledProvider = input<(dropdownOption: T) => boolean>(() => false);
 
  override readonly allRows = computed(() => {
    const complexOptions = this.complexOptions();
    if (complexOptions instanceof Array) {
      return this.convertOptionsArray(complexOptions);
    } else if (complexOptions) {
      const groupProvider = this.groupProvider();
      return Object.entries(complexOptions).map(
        ([key, value]) =>
          ({
            type: 'group',
            key,
            label: groupProvider(key) ?? key,
            options: this.convertOptionsArray(value)
          }) as SelectGroup<T>
      );
    } else {
      return [];
    }
  });
 
  ngOnChanges(): void {
    this.onFilter();
  }
 
  private convertOptionsArray(options: T[]): SelectOption<T>[] {
    const provide = this.valueProvider();
    return options.map(option => {
      return {
        type: 'option',
        value: option,
        label: (provide ? provide(option) : undefined) ?? option + '',
        typeaheadLabel: provide ? provide(option) : undefined,
        disabled: this.disabledProvider()(option)
      };
    });
  }
}