UNPKG

@ionic/angular

Version:

Angular specific wrappers for @ionic/core

152 lines 5.82 kB
import { Directive, HostListener } from '@angular/core'; import { NgControl } from '@angular/forms'; import { raf } from '../../utils/util'; import * as i0 from "@angular/core"; // TODO(FW-2827): types export class ValueAccessor { injector; elementRef; onChange = () => { /**/ }; onTouched = () => { /**/ }; lastValue; statusChanges; constructor(injector, elementRef) { this.injector = injector; this.elementRef = elementRef; } writeValue(value) { this.elementRef.nativeElement.value = this.lastValue = value; setIonicClasses(this.elementRef); } /** * Notifies the ControlValueAccessor of a change in the value of the control. * * This is called by each of the ValueAccessor directives when we want to update * the status and validity of the form control. For example with text components this * is called when the ionInput event is fired. For select components this is called * when the ionChange event is fired. * * This also updates the Ionic form status classes on the element. * * @param el The component element. * @param value The new value of the control. */ handleValueChange(el, value) { if (el === this.elementRef.nativeElement) { if (value !== this.lastValue) { this.lastValue = value; this.onChange(value); } setIonicClasses(this.elementRef); } } _handleBlurEvent(el) { if (el === this.elementRef.nativeElement) { this.onTouched(); setIonicClasses(this.elementRef); // When ion-radio is blurred, el and this.elementRef.nativeElement are // different so we need to check if the closest ion-radio-group is the same // as this.elementRef.nativeElement and if so, we need to mark the radio group // as touched } else if (el.closest('ion-radio-group') === this.elementRef.nativeElement) { this.onTouched(); } } registerOnChange(fn) { this.onChange = fn; } registerOnTouched(fn) { this.onTouched = fn; } setDisabledState(isDisabled) { this.elementRef.nativeElement.disabled = isDisabled; } ngOnDestroy() { if (this.statusChanges) { this.statusChanges.unsubscribe(); } } ngAfterViewInit() { let ngControl; try { ngControl = this.injector.get(NgControl); } catch { /* No FormControl or ngModel binding */ } if (!ngControl) { return; } // Listen for changes in validity, disabled, or pending states if (ngControl.statusChanges) { this.statusChanges = ngControl.statusChanges.subscribe(() => setIonicClasses(this.elementRef)); } /** * TODO FW-2787: Remove this in favor of https://github.com/angular/angular/issues/10887 * whenever it is implemented. */ const formControl = ngControl.control; if (formControl) { const methodsToPatch = ['markAsTouched', 'markAllAsTouched', 'markAsUntouched', 'markAsDirty', 'markAsPristine']; methodsToPatch.forEach((method) => { if (typeof formControl[method] !== 'undefined') { const oldFn = formControl[method].bind(formControl); formControl[method] = (...params) => { oldFn(...params); setIonicClasses(this.elementRef); }; } }); } } /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: ValueAccessor, deps: [{ token: i0.Injector }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); /** @nocollapse */ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.0", type: ValueAccessor, isStandalone: true, host: { listeners: { "ionBlur": "_handleBlurEvent($event.target)" } }, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: ValueAccessor, decorators: [{ type: Directive }], ctorParameters: () => [{ type: i0.Injector }, { type: i0.ElementRef }], propDecorators: { _handleBlurEvent: [{ type: HostListener, args: ['ionBlur', ['$event.target']] }] } }); export const setIonicClasses = (element) => { raf(() => { const input = element.nativeElement; const hasValue = input.value != null && input.value.toString().length > 0; const classes = getClasses(input); setClasses(input, classes); const item = input.closest('ion-item'); if (item) { if (hasValue) { setClasses(item, [...classes, 'item-has-value']); } else { setClasses(item, classes); } } }); }; const getClasses = (element) => { const classList = element.classList; const classes = []; for (let i = 0; i < classList.length; i++) { const item = classList.item(i); if (item !== null && startsWith(item, 'ng-')) { classes.push(`ion-${item.substring(3)}`); } } return classes; }; const setClasses = (element, classes) => { const classList = element.classList; classList.remove('ion-valid', 'ion-invalid', 'ion-touched', 'ion-untouched', 'ion-dirty', 'ion-pristine'); classList.add(...classes); }; const startsWith = (input, search) => { return input.substring(0, search.length) === search; }; //# sourceMappingURL=value-accessor.js.map