import { AfterContentInit , ChangeDetectionStrategy , ChangeDetectorRef , ContentChild , ContentChildren , EventEmitter , HostBinding , Output , QueryList , TemplateRef , ViewChildren , } from '@angular/core' ; import { Component , HostListener , Input } from '@angular/core' ; import { ControlValueAccessor , NG_VALUE_ACCESSOR } from '@angular/forms' ; import { ListItemTemplateDirective } from '../../list/list.directive' ; import { RadioComponent } from '../radio.component' ; @ Component ( { selector : 'kirby-radio-group' , templateUrl : './radio-group.component.html' , styles : [ 'ion-radio-group { display: inherit; flex-wrap: inherit}' ] , providers : [ { provide : NG_VALUE_ACCESSOR , useExisting : RadioGroupComponent , multi : true , } , ] , changeDetection : ChangeDetectionStrategy . OnPush , } ) export class RadioGroupComponent implements AfterContentInit , ControlValueAccessor { constructor ( private changeDetectionRef ) { } get disabled ( ) : boolean { return this . _disabled ; } @ Input ( ) set disabled ( value ) { this . _disabled = value ; this . setProjectedRadiosDisabledState ( value ) ; } @ HostBinding ( 'class.error' ) @ Input ( ) hasError : boolean = false ; get items ( ) : string [ ] | any [ ] { return this . _items || [ ] ; } @ Input ( ) set items ( value ) { if ( ( ! value || ! value . length ) && ! this . items . length ) return ; this . _items = value ; this . refreshSelectionState ( ) ; } @ Input ( ) itemTextProperty = 'text' ; @ Input ( ) itemDisabledProperty = 'disabled' ; get selectedIndex ( ) : number { return this . _selectedIndex ; } @ Input ( ) set selectedIndex ( value ) { if ( typeof value === 'string' ) value = parseInt ( value ) ; if ( value === undefined || value === null || value === NaN ) value = - 1 ; if ( value === this . selectedIndex ) return ; this . _selectedIndex = value ; this . _value = this . getValueFromSelectedIndex ( ) || null ; } get value ( ) : string | any { return this . _value ; } @ Input ( ) set value ( value ) { this . setSelectedItem ( value ) ; } private get hasValue ( ) : boolean { return this . value !== undefined && this . value !== null ; } /**
     * Emitted when an option is selected
     */ @ Output ( ) valueChange : EventEmitter < string | any > = new EventEmitter < string | any > ( ) ; @ ContentChild ( ListItemTemplateDirective , { read : TemplateRef } ) _customItemTemplate : TemplateRef < any > ; private _disabled = false ; private _items : string [ ] | any [ ] = [ ] ; private _onChangeCallback : ( value : any ) => void = ( ) => { } ; private _onTouched = ( ) => { } ; private _selectedIndex : number = - 1 ; private _value ? : string | any = null ; @ ViewChildren ( RadioComponent ) private radioButtons : QueryList < RadioComponent > ; @ ContentChildren ( RadioComponent , { descendants : true } ) private projectedRadioButtons : QueryList < RadioComponent > ; private get hasItemsFromContentProjection ( ) : boolean { return ( ! this . items . length && ! this . _customItemTemplate && this . projectedRadioButtons && this . projectedRadioButtons . length > 0 ) ; } focus ( ) { const findFocusable = ( radios ) => radios && radios . find ( ( radio ) => ! isNaN ( radio . buttonTabIndex ) && radio . buttonTabIndex !== - 1 ) ; const focusable = findFocusable ( this . radioButtons ) || findFocusable ( this . projectedRadioButtons ) ; focusable && focusable . focus ( ) ; } ngAfterContentInit ( ) { this . initSelectionStateFromProjectedContent ( ) ; this . listenForProjectedRadiosChange ( ) ; } registerOnChange ( fn ) { this . _onChangeCallback = fn ; } registerOnTouched ( fn ) { this . _onTouched = fn ; } setDisabledState ( isDisabled ) { this . disabled = isDisabled ; this . changeDetectionRef . markForCheck ( ) ; } writeValue ( value ) { this . value = value ; this . changeDetectionRef . markForCheck ( ) ; } _getTextFromItem ( item ) { if ( ! item ) return null ; return typeof item === 'string' ? item : item [ this . itemTextProperty ] ; } _getDisabledStateFromItem ( item ) { if ( ! item ) return undefined ; return typeof item === 'string' ? undefined : item [ this . itemDisabledProperty ] ; } get _hasItems ( ) : boolean { return this . items . length > 0 || this . hasItemsFromContentProjection ; } _onChange ( value ) { if ( value === this . _value ) return ; this . setSelectedItem ( value ) ; this . valueChange . emit ( value ) ; this . _onChangeCallback ( value ) ; } @ HostListener ( 'ionBlur' ) _onRadioBlur ( ) { this . _onTouched ( ) ; } private getIndexOfSelectedValue ( ) { if ( ! this . hasValue ) return - 1 ; return this . hasItemsFromContentProjection ? this . getIndexOfProjectedRadio ( this . value ) : this . items . indexOf ( this . value ) ; } private getIndexOfProjectedRadio ( value ) { let selectedIndex = - 1 ; this . projectedRadioButtons && this . projectedRadioButtons . find ( ( radio , i ) => { const found = radio . value === value ; if ( found ) { selectedIndex = i ; } return found ; } ) ; return selectedIndex ; } private getValueFromSelectedIndex ( ) { if ( this . selectedIndex === - 1 ) return ; return this . hasItemsFromContentProjection ? this . getValueFromProjectedRadios ( this . selectedIndex ) : this . items [ this . selectedIndex ] ; } private getValueFromProjectedRadios ( index ) { const radio = this . projectedRadioButtons && this . projectedRadioButtons . find ( ( _ , i ) => { return i === index ; } ) ; return radio && radio . value ; } private initSelectionStateFromProjectedContent ( ) { if ( this . hasItemsFromContentProjection ) { this . refreshSelectionState ( ) ; } } private listenForProjectedRadiosChange ( ) { this . projectedRadioButtons . changes . subscribe ( ( ) => { this . refreshStateFromProjectedContent ( ) ; if ( this . disabled ) { setTimeout ( ( ) => this . setProjectedRadiosDisabledState ( this . disabled ) ) ; } } ) ; } private refreshSelectionState ( ) { if ( this . hasValue ) { this . _selectedIndex = this . getIndexOfSelectedValue ( ) ; } const valueFromSelectedIndex = this . getValueFromSelectedIndex ( ) ; this . _value = valueFromSelectedIndex !== undefined ? valueFromSelectedIndex : null ; } private refreshStateFromProjectedContent ( ) { if ( ! ! this . _customItemTemplate ) return ; this . changeDetectionRef . markForCheck ( ) ; this . refreshSelectionState ( ) ; } private setSelectedItem ( value ) { if ( value === this . _value ) return ; this . _value = value ; this . _selectedIndex = this . getIndexOfSelectedValue ( ) ; } private setProjectedRadiosDisabledState ( isDisabled ) { if ( ! this . projectedRadioButtons || ! this . projectedRadioButtons . length ) return ; this . projectedRadioButtons . forEach ( ( radio , index ) => { radio . disabled = isDisabled || this . _getDisabledStateFromItem ( this . items [ index ] ) ; } ) ; } }