All files / lib/radio-button-group radio-button.component.ts

91.87% Statements 147/160
90% Branches 18/20
81.81% Functions 9/11
91.87% Lines 147/160

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 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 1611x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x         1x 1x 1x 1x 209x 209x 209x 209x 209x 209x 209x 2x 209x 209x 209x 209x 209x 1x 1x 1x     1x 1x 1x     1x 1x 1x 10x 10x 10x 10x 10x 10x 10x 10x 10x           10x 10x 1x 1x 1x 21x 21x 1x  
/*******************************************************************************
 * Copyright bei
 * Entwicklungs- und Pflegeverbund für das gemeinsame Fachverfahren gefa
 *
 *******************************************************************************/
import {
  Component,
  ElementRef,
  EventEmitter,
  Input,
  NgZone,
  OnInit,
  Output,
  ViewChild,
} from '@angular/core';
 
import { FocusableElementOwner } from '../utils/util.types';
 
/**
 * A single radio button element that allows the user to select an option.
 */
@Component({
  selector: 'gc-radio-button',
  templateUrl: './radio-button.component.html',
  styleUrls: ['./radio-button.component.css'],
  standalone: false,
})
export class RadioButtonComponent implements FocusableElementOwner, OnInit {
  @Input()
  public id?: string;
 
  /**
   * Hides the label of the radio button. May be used for embedded rendering like in tables.
   */
  @Input()
  public hideLabel = false;
 
  /**
   * Text that will show near the radio button
   */
  @Input()
  public label = '';
 
  /**
   * Decides if the radio button will be rendered in a disabled/enabled state
   */
  @Input()
  public disabled = false;
 
  /**
   * The value represents the selection state: true == checked, false == unchecked
   */
  @Input()
  public value = false;
 
  /**
   * Decides if the radio button will be rendered in a readonly state
   * @deprecated
   */
  @Input()
  public readonly = false;
 
  /**
   * Decides if the radio button will be rendered in an error state
   */
  @Input()
  public error = false;
 
  /**
   * Marks the input field as required.
   */
  @Input()
  public required = false;
 
  /**
   * Inform about the change of the selection state
   */
  @Output()
  public readonly valueChange: EventEmitter<boolean> =
    new EventEmitter<boolean>();
 
  /**
   * @ignore
   */
  @Input()
  public radioButtonGroupId?: string;
 
  /**
   * Enables setting of the value only when the Promise resolves with value "true".
   */
  @Input()
  public permitSelection?: () => Promise<boolean> | boolean;
 
  /** @ignore */
  @ViewChild('input')
  protected inputElement!: ElementRef<HTMLInputElement>;
 
  /** @ignore */
  protected _hasFocus = false;
 
  public constructor(private readonly zone: NgZone) {}
 
  public focusChild(): boolean {
    if (!this.disabled) {
      this.inputElement.nativeElement.focus();
      return true;
    }
    return false;
  }
 
  /** @ignore */
  public ngOnInit(): void {
    // browser may "restore" previous values after navigating (e.g. with browser's "back" button),
    // potentially leading to an inconsistent state as no events are fired which could be used to
    // detect this (observed on Chromium) -> sync back state to the native element after it's rendered
    this.zone.runOutsideAngular(() => {
      setTimeout(() => {
        setTimeout(() => {
          if (this.value !== this.inputElement.nativeElement.checked) {
            this.inputElement.nativeElement.checked = this.value;
          }
        });
      });
    });
  }
 
  /** @ignore */
  public _refreshNativeElement(): void {
    this.inputElement.nativeElement.checked = this.value;
  }
 
  /** @ignore */
  protected handleClick(event: MouseEvent) {
    event.stopPropagation();
  }
 
  /** @ignore */
  protected async _onClick(): Promise<void> {
    const doChange = () => {
      this.inputElement.nativeElement.focus();
      this.value = true;
      this.valueChange.emit(this.value);
    };
    if (this.permitSelection) {
      const permit = await this.permitSelection();
      if (permit) {
        doChange();
      } else {
        this._refreshNativeElement();
      }
    } else {
      doChange();
    }
  }
 
  /** @ignore */
  protected _setFocus(focused: boolean) {
    this._hasFocus = focused;
  }
}