import { AfterContentInit , ChangeDetectorRef , ContentChildren , Directive , EventEmitter , ExistingProvider , forwardRef , Input , OnDestroy , Output , QueryList } from '@angular/core' ; import { ControlValueAccessor , NG_VALUE_ACCESSOR } from '@angular/forms' ; import { Subject } from 'rxjs' ; import { takeUntil } from 'rxjs/operators' ; import { RadioButtonComponent } from '../radiobutton.component' ; export const RADIO_GROUP_CONTROL_VALUE_ACCESSOR = { provide : NG_VALUE_ACCESSOR , useExisting : forwardRef ( ( ) => RadioButtonGroupDirective ) , multi : true } ; @ Directive ( { selector : 'ux-radio-button-group, [uxRadioButtonGroup]' , providers : [ RADIO_GROUP_CONTROL_VALUE_ACCESSOR ] , host : { 'role' : 'radiogroup' } } ) export class RadioButtonGroupDirective < T = any > implements ControlValueAccessor , AfterContentInit , OnDestroy { /** Define the current selected value within the group */ @ Input ( ) set value ( value ) { this . _value = value ; this . updateSelectedRadioButton ( ) ; } /** Return the currently selected value */ get value ( ) : T { return this . _value ; } /** Emit when the currently selected value changes */ @ Output ( ) valueChange = new EventEmitter < T > ( ) ; /** Used to inform Angular forms that the component has been touched */ onTouched : ( ) => void = ( ) => { } ; /** Used to inform Angular forms that the component value has changed */ onChange : ( value : any ) => void = ( ) => { } ; @ ContentChildren ( forwardRef ( ( ) => RadioButtonComponent ) , { descendants : true } ) _radioButtons : QueryList < RadioButtonComponent > ; /** Unsubscribe from all subscriptions on destroy */ private readonly _onDestroy$ = new Subject < void > ( ) ; /** Internally store the current value */ private _value : T = null ; constructor ( private readonly _changeDetector ) { } ngAfterContentInit ( ) { this . updateSelectedRadioButton ( ) ; this . _radioButtons . changes . pipe ( takeUntil ( this . _onDestroy$ ) ) . subscribe ( ( ) => this . updateSelectedRadioButton ( ) ) ; } ngOnDestroy ( ) { this . _onDestroy$ . next ( ) ; this . _onDestroy$ . complete ( ) ; } /** Allow Angular forms for provide us with a callback for when the input value changes */ registerOnChange ( fn ) { this . onChange = fn ; } /** Allow Angular forms for provide us with a callback for when the touched state changes */ registerOnTouched ( fn ) { this . onTouched = fn ; } /** Allow Angular forms to give us the current value */ writeValue ( value ) { this . value = value ; this . _changeDetector . markForCheck ( ) ; } /** Allow Angular forms to disable the component */ setDisabledState ( isDisabled ) { if ( this . _radioButtons ) { this . _radioButtons . forEach ( radio => radio . setDisabledState ( isDisabled ) ) ; this . _changeDetector . markForCheck ( ) ; } } /** Emit the currently selected value */ emitChange ( value ) { this . valueChange . next ( value ) ; this . onChange ( value ) ; this . onTouched ( ) ; } /** Inform all child radio buttons of the latest value */ private updateSelectedRadioButton ( ) { if ( this . _radioButtons ) { this . _radioButtons . forEach ( radio => radio . writeValue ( this . _value ) ) ; } } }