From aaa7af2d8a47ba14f4e2150510673b15a6846800 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Mon, 30 Oct 2023 13:30:33 -0400 Subject: [PATCH 1/6] fix(angular): inputs on standalone form controls are reactive --- packages/angular/standalone/src/directives/checkbox.ts | 9 +++------ packages/angular/standalone/src/directives/datetime.ts | 10 +++------- packages/angular/standalone/src/directives/input.ts | 10 +++------- .../angular/standalone/src/directives/radio-group.ts | 10 +++------- packages/angular/standalone/src/directives/radio.ts | 10 +++------- packages/angular/standalone/src/directives/range.ts | 10 +++------- .../angular/standalone/src/directives/searchbar.ts | 10 +++------- packages/angular/standalone/src/directives/segment.ts | 10 +++------- packages/angular/standalone/src/directives/select.ts | 10 +++------- packages/angular/standalone/src/directives/textarea.ts | 10 +++------- packages/angular/standalone/src/directives/toggle.ts | 10 +++------- 11 files changed, 33 insertions(+), 76 deletions(-) diff --git a/packages/angular/standalone/src/directives/checkbox.ts b/packages/angular/standalone/src/directives/checkbox.ts index 218c0483ee1..f9ba7fe0c46 100644 --- a/packages/angular/standalone/src/directives/checkbox.ts +++ b/packages/angular/standalone/src/directives/checkbox.ts @@ -8,7 +8,6 @@ import { Injector, NgZone, } from '@angular/core'; -import type { OnInit } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor, setIonicClasses } from '@ionic/angular/common'; import type { CheckboxChangeEventDetail, Components } from '@ionic/core/components'; @@ -56,23 +55,21 @@ const CHECKBOX_INPUTS = [ ], standalone: true, }) -export class IonCheckbox extends ValueAccessor implements OnInit { +export class IonCheckbox extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); defineCustomElement(); c.detach(); this.el = r.nativeElement; - proxyOutputs(this, this.el, ['ionChange', 'ionFocus', 'ionBlur']); - } - ngOnInit(): void { /** * Data-bound input properties are set * by Angular after the constructor, so - * we need to run the proxy in ngOnInit. + * we need to run the proxy before ngOnInit. */ proxyInputs(IonCheckbox, CHECKBOX_INPUTS); + proxyOutputs(this, this.el, ['ionChange', 'ionFocus', 'ionBlur']); } writeValue(value: boolean): void { diff --git a/packages/angular/standalone/src/directives/datetime.ts b/packages/angular/standalone/src/directives/datetime.ts index 4f476d7b4e2..e09b2b3a971 100644 --- a/packages/angular/standalone/src/directives/datetime.ts +++ b/packages/angular/standalone/src/directives/datetime.ts @@ -8,7 +8,6 @@ import { Injector, NgZone, } from '@angular/core'; -import type { OnInit } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor } from '@ionic/angular/common'; import type { DatetimeChangeEventDetail, Components } from '@ionic/core/components'; @@ -78,24 +77,21 @@ const DATETIME_METHODS = ['confirm', 'reset', 'cancel']; ], standalone: true, }) -export class IonDatetime extends ValueAccessor implements OnInit { +export class IonDatetime extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); defineCustomElement(); c.detach(); this.el = r.nativeElement; - proxyOutputs(this, this.el, ['ionCancel', 'ionChange', 'ionFocus', 'ionBlur']); - } - - ngOnInit(): void { /** * Data-bound input properties are set * by Angular after the constructor, so - * we need to run the proxy in ngOnInit. + * we need to run the proxy before ngOnInit. */ proxyInputs(IonDatetime, DATETIME_INPUTS); proxyMethods(IonDatetime, DATETIME_METHODS); + proxyOutputs(this, this.el, ['ionCancel', 'ionChange', 'ionFocus', 'ionBlur']); } @HostListener('ionChange', ['$event.target']) diff --git a/packages/angular/standalone/src/directives/input.ts b/packages/angular/standalone/src/directives/input.ts index 8fb920eddbb..1d1738993f8 100644 --- a/packages/angular/standalone/src/directives/input.ts +++ b/packages/angular/standalone/src/directives/input.ts @@ -8,7 +8,6 @@ import { Injector, NgZone, } from '@angular/core'; -import type { OnInit } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor } from '@ionic/angular/common'; import type { @@ -89,24 +88,21 @@ const INPUT_METHODS = ['setFocus', 'getInputElement']; ], standalone: true, }) -export class IonInput extends ValueAccessor implements OnInit { +export class IonInput extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); defineCustomElement(); c.detach(); this.el = r.nativeElement; - proxyOutputs(this, this.el, ['ionInput', 'ionChange', 'ionBlur', 'ionFocus']); - } - - ngOnInit(): void { /** * Data-bound input properties are set * by Angular after the constructor, so - * we need to run the proxy in ngOnInit. + * we need to run the proxy before ngOnInit. */ proxyInputs(IonInput, INPUT_INPUTS); proxyMethods(IonInput, INPUT_METHODS); + proxyOutputs(this, this.el, ['ionInput', 'ionChange', 'ionBlur', 'ionFocus']); } @HostListener('ionInput', ['$event.target']) diff --git a/packages/angular/standalone/src/directives/radio-group.ts b/packages/angular/standalone/src/directives/radio-group.ts index 2c6870aa16e..5cced80f285 100644 --- a/packages/angular/standalone/src/directives/radio-group.ts +++ b/packages/angular/standalone/src/directives/radio-group.ts @@ -8,7 +8,6 @@ import { Injector, NgZone, } from '@angular/core'; -import type { OnInit } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor } from '@ionic/angular/common'; import type { RadioGroupChangeEventDetail, Components } from '@ionic/core/components'; @@ -45,23 +44,20 @@ const RADIO_GROUP_INPUTS = ['allowEmptySelection', 'name', 'value']; ], standalone: true, }) -export class IonRadioGroup extends ValueAccessor implements OnInit { +export class IonRadioGroup extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); defineCustomElement(); c.detach(); this.el = r.nativeElement; - proxyOutputs(this, this.el, ['ionChange']); - } - - ngOnInit(): void { /** * Data-bound input properties are set * by Angular after the constructor, so - * we need to run the proxy in ngOnInit. + * we need to run the proxy before ngOnInit. */ proxyInputs(IonRadioGroup, RADIO_GROUP_INPUTS); + proxyOutputs(this, this.el, ['ionChange']); } @HostListener('ionChange', ['$event.target']) diff --git a/packages/angular/standalone/src/directives/radio.ts b/packages/angular/standalone/src/directives/radio.ts index d70ea8d01df..55cdac06302 100644 --- a/packages/angular/standalone/src/directives/radio.ts +++ b/packages/angular/standalone/src/directives/radio.ts @@ -8,7 +8,6 @@ import { Injector, NgZone, } from '@angular/core'; -import type { OnInit } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor } from '@ionic/angular/common'; import type { Components } from '@ionic/core/components'; @@ -45,23 +44,20 @@ const RADIO_INPUTS = ['color', 'disabled', 'justify', 'labelPlacement', 'legacy' ], standalone: true, }) -export class IonRadio extends ValueAccessor implements OnInit { +export class IonRadio extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); defineCustomElement(); c.detach(); this.el = r.nativeElement; - proxyOutputs(this, this.el, ['ionFocus', 'ionBlur']); - } - - ngOnInit(): void { /** * Data-bound input properties are set * by Angular after the constructor, so - * we need to run the proxy in ngOnInit. + * we need to run the proxy before ngOnInit. */ proxyInputs(IonRadio, RADIO_INPUTS); + proxyOutputs(this, this.el, ['ionFocus', 'ionBlur']); } @HostListener('ionSelect', ['$event.target']) diff --git a/packages/angular/standalone/src/directives/range.ts b/packages/angular/standalone/src/directives/range.ts index f77beecbe4b..14aa556dadf 100644 --- a/packages/angular/standalone/src/directives/range.ts +++ b/packages/angular/standalone/src/directives/range.ts @@ -8,7 +8,6 @@ import { Injector, NgZone, } from '@angular/core'; -import type { OnInit } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor } from '@ionic/angular/common'; import type { @@ -69,23 +68,20 @@ const RANGE_INPUTS = [ ], standalone: true, }) -export class IonRange extends ValueAccessor implements OnInit { +export class IonRange extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); defineCustomElement(); c.detach(); this.el = r.nativeElement; - proxyOutputs(this, this.el, ['ionChange', 'ionInput', 'ionFocus', 'ionBlur', 'ionKnobMoveStart', 'ionKnobMoveEnd']); - } - - ngOnInit(): void { /** * Data-bound input properties are set * by Angular after the constructor, so - * we need to run the proxy in ngOnInit. + * we need to run the proxy before ngOnInit. */ proxyInputs(IonRange, RANGE_INPUTS); + proxyOutputs(this, this.el, ['ionChange', 'ionInput', 'ionFocus', 'ionBlur', 'ionKnobMoveStart', 'ionKnobMoveEnd']); } @HostListener('ionChange', ['$event.target']) diff --git a/packages/angular/standalone/src/directives/searchbar.ts b/packages/angular/standalone/src/directives/searchbar.ts index 75f1d7da671..66ac9c3048c 100644 --- a/packages/angular/standalone/src/directives/searchbar.ts +++ b/packages/angular/standalone/src/directives/searchbar.ts @@ -8,7 +8,6 @@ import { Injector, NgZone, } from '@angular/core'; -import type { OnInit } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor } from '@ionic/angular/common'; import type { SearchbarInputEventDetail, SearchbarChangeEventDetail, Components } from '@ionic/core/components'; @@ -68,24 +67,21 @@ const SEARCHBAR_METHODS = ['setFocus', 'getInputElement']; ], standalone: true, }) -export class IonSearchbar extends ValueAccessor implements OnInit { +export class IonSearchbar extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); defineCustomElement(); c.detach(); this.el = r.nativeElement; - proxyOutputs(this, this.el, ['ionInput', 'ionChange', 'ionCancel', 'ionClear', 'ionBlur', 'ionFocus']); - } - - ngOnInit(): void { /** * Data-bound input properties are set * by Angular after the constructor, so - * we need to run the proxy in ngOnInit. + * we need to run the proxy before ngOnInit. */ proxyInputs(IonSearchbar, SEARCHBAR_INPUTS); proxyMethods(IonSearchbar, SEARCHBAR_METHODS); + proxyOutputs(this, this.el, ['ionInput', 'ionChange', 'ionCancel', 'ionClear', 'ionBlur', 'ionFocus']); } @HostListener('ionInput', ['$event.target']) diff --git a/packages/angular/standalone/src/directives/segment.ts b/packages/angular/standalone/src/directives/segment.ts index 5d6a16f77c0..8fd01dfcd05 100644 --- a/packages/angular/standalone/src/directives/segment.ts +++ b/packages/angular/standalone/src/directives/segment.ts @@ -8,7 +8,6 @@ import { Injector, NgZone, } from '@angular/core'; -import type { OnInit } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor } from '@ionic/angular/common'; import type { SegmentChangeEventDetail, Components } from '@ionic/core/components'; @@ -45,23 +44,20 @@ const SEGMENT_INPUTS = ['color', 'disabled', 'mode', 'scrollable', 'selectOnFocu ], standalone: true, }) -export class IonSegment extends ValueAccessor implements OnInit { +export class IonSegment extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); defineCustomElement(); c.detach(); this.el = r.nativeElement; - proxyOutputs(this, this.el, ['ionChange']); - } - - ngOnInit(): void { /** * Data-bound input properties are set * by Angular after the constructor, so - * we need to run the proxy in ngOnInit. + * we need to run the proxy before ngOnInit. */ proxyInputs(IonSegment, SEGMENT_INPUTS); + proxyOutputs(this, this.el, ['ionChange']); } @HostListener('ionChange', ['$event.target']) diff --git a/packages/angular/standalone/src/directives/select.ts b/packages/angular/standalone/src/directives/select.ts index 0041f91d863..6a896820d5e 100644 --- a/packages/angular/standalone/src/directives/select.ts +++ b/packages/angular/standalone/src/directives/select.ts @@ -8,7 +8,6 @@ import { Injector, NgZone, } from '@angular/core'; -import type { OnInit } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor } from '@ionic/angular/common'; import type { SelectChangeEventDetail, Components } from '@ionic/core/components'; @@ -69,24 +68,21 @@ const SELECT_METHODS = ['open']; ], standalone: true, }) -export class IonSelect extends ValueAccessor implements OnInit { +export class IonSelect extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); defineCustomElement(); c.detach(); this.el = r.nativeElement; - proxyOutputs(this, this.el, ['ionChange', 'ionCancel', 'ionDismiss', 'ionFocus', 'ionBlur']); - } - - ngOnInit(): void { /** * Data-bound input properties are set * by Angular after the constructor, so - * we need to run the proxy in ngOnInit. + * we need to run the proxy before ngOnInit. */ proxyInputs(IonSelect, SELECT_INPUTS); proxyMethods(IonSelect, SELECT_METHODS); + proxyOutputs(this, this.el, ['ionChange', 'ionCancel', 'ionDismiss', 'ionFocus', 'ionBlur']); } @HostListener('ionChange', ['$event.target']) diff --git a/packages/angular/standalone/src/directives/textarea.ts b/packages/angular/standalone/src/directives/textarea.ts index af5d8b49967..9c590d1f87c 100644 --- a/packages/angular/standalone/src/directives/textarea.ts +++ b/packages/angular/standalone/src/directives/textarea.ts @@ -8,7 +8,6 @@ import { Injector, NgZone, } from '@angular/core'; -import type { OnInit } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor } from '@ionic/angular/common'; import type { TextareaChangeEventDetail, TextareaInputEventDetail, Components } from '@ionic/core/components'; @@ -78,24 +77,21 @@ const TEXTAREA_METHODS = ['setFocus', 'getInputElement']; ], standalone: true, }) -export class IonTextarea extends ValueAccessor implements OnInit { +export class IonTextarea extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); defineCustomElement(); c.detach(); this.el = r.nativeElement; - proxyOutputs(this, this.el, ['ionChange', 'ionInput', 'ionBlur', 'ionFocus']); - } - - ngOnInit(): void { /** * Data-bound input properties are set * by Angular after the constructor, so - * we need to run the proxy in ngOnInit. + * we need to run the proxy before ngOnInit. */ proxyInputs(IonTextarea, TEXTAREA_INPUTS); proxyMethods(IonTextarea, TEXTAREA_METHODS); + proxyOutputs(this, this.el, ['ionChange', 'ionInput', 'ionBlur', 'ionFocus']); } @HostListener('ionInput', ['$event.target']) diff --git a/packages/angular/standalone/src/directives/toggle.ts b/packages/angular/standalone/src/directives/toggle.ts index 1736200650f..d9f2787cfd9 100644 --- a/packages/angular/standalone/src/directives/toggle.ts +++ b/packages/angular/standalone/src/directives/toggle.ts @@ -8,7 +8,6 @@ import { Injector, NgZone, } from '@angular/core'; -import type { OnInit } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor, setIonicClasses } from '@ionic/angular/common'; import type { ToggleChangeEventDetail, Components } from '@ionic/core/components'; @@ -56,23 +55,20 @@ const TOGGLE_INPUTS = [ ], standalone: true, }) -export class IonToggle extends ValueAccessor implements OnInit { +export class IonToggle extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); defineCustomElement(); c.detach(); this.el = r.nativeElement; - proxyOutputs(this, this.el, ['ionChange', 'ionFocus', 'ionBlur']); - } - - ngOnInit(): void { /** * Data-bound input properties are set * by Angular after the constructor, so - * we need to run the proxy in ngOnInit. + * we need to run the proxy before ngOnInit. */ proxyInputs(IonToggle, TOGGLE_INPUTS); + proxyOutputs(this, this.el, ['ionChange', 'ionFocus', 'ionBlur']); } writeValue(value: boolean): void { From c7c38c2974c55996f18c58d594656e91776c6b06 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Mon, 30 Oct 2023 14:18:08 -0400 Subject: [PATCH 2/6] revert --- .../standalone/src/directives/checkbox.ts | 26 ++----- .../standalone/src/directives/datetime.ts | 29 ++------ .../standalone/src/directives/input.ts | 29 ++------ .../standalone/src/directives/radio-group.ts | 25 ++----- .../standalone/src/directives/radio.ts | 25 ++----- .../standalone/src/directives/range.ts | 25 ++----- .../standalone/src/directives/searchbar.ts | 29 ++------ .../standalone/src/directives/segment.ts | 25 ++----- .../standalone/src/directives/select.ts | 29 ++------ .../standalone/src/directives/textarea.ts | 29 ++------ .../standalone/src/directives/toggle.ts | 25 ++----- .../src/standalone/value-accessors.spec.ts | 67 ------------------- .../standalone/app-standalone/app.routes.ts | 1 - .../checkbox/checkbox.component.html | 2 +- .../datetime/datetime.component.html | 2 +- .../input/input.component.html | 2 +- .../radio-group/radio-group.component.html | 2 +- .../range/range.component.html | 2 +- .../searchbar/searchbar.component.html | 2 +- .../segment/segment.component.html | 2 +- .../select/select.component.html | 14 ---- .../select/select.component.ts | 26 ------- .../textarea/textarea.component.html | 2 +- .../toggle/toggle.component.html | 2 +- 24 files changed, 69 insertions(+), 353 deletions(-) delete mode 100644 packages/angular/test/base/src/app/standalone/value-accessors/select/select.component.html delete mode 100644 packages/angular/test/base/src/app/standalone/value-accessors/select/select.component.ts diff --git a/packages/angular/standalone/src/directives/checkbox.ts b/packages/angular/standalone/src/directives/checkbox.ts index f9ba7fe0c46..26f139f379b 100644 --- a/packages/angular/standalone/src/directives/checkbox.ts +++ b/packages/angular/standalone/src/directives/checkbox.ts @@ -13,19 +13,7 @@ import { ValueAccessor, setIonicClasses } from '@ionic/angular/common'; import type { CheckboxChangeEventDetail, Components } from '@ionic/core/components'; import { defineCustomElement } from '@ionic/core/components/ion-checkbox.js'; -/** - * Value accessor components should not use ProxyCmp - * and should call defineCustomElement and proxyInputs - * manually instead. Using both the @ProxyCmp and @Component - * decorators and useExisting (where useExisting refers to the - * class) causes ng-packagr to output multiple component variables - * which breaks treeshaking. - * For example, the following would be generated: - * let IonCheckbox = IonCheckbox_1 = class IonCheckbox extends ValueAccessor { - * Instead, we want only want the class generated: - * class IonCheckbox extends ValueAccessor { - */ -import { proxyInputs, proxyOutputs } from './angular-component-lib/utils'; +import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; const CHECKBOX_INPUTS = [ 'checked', @@ -40,6 +28,10 @@ const CHECKBOX_INPUTS = [ 'value', ]; +@ProxyCmp({ + defineCustomElementFn: defineCustomElement, + inputs: CHECKBOX_INPUTS, +}) @Component({ selector: 'ion-checkbox', changeDetection: ChangeDetectionStrategy.OnPush, @@ -59,16 +51,8 @@ export class IonCheckbox extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); - defineCustomElement(); c.detach(); this.el = r.nativeElement; - - /** - * Data-bound input properties are set - * by Angular after the constructor, so - * we need to run the proxy before ngOnInit. - */ - proxyInputs(IonCheckbox, CHECKBOX_INPUTS); proxyOutputs(this, this.el, ['ionChange', 'ionFocus', 'ionBlur']); } diff --git a/packages/angular/standalone/src/directives/datetime.ts b/packages/angular/standalone/src/directives/datetime.ts index e09b2b3a971..57068f71b97 100644 --- a/packages/angular/standalone/src/directives/datetime.ts +++ b/packages/angular/standalone/src/directives/datetime.ts @@ -13,19 +13,7 @@ import { ValueAccessor } from '@ionic/angular/common'; import type { DatetimeChangeEventDetail, Components } from '@ionic/core/components'; import { defineCustomElement } from '@ionic/core/components/ion-datetime.js'; -/** - * Value accessor components should not use ProxyCmp - * and should call defineCustomElement and proxyInputs - * manually instead. Using both the @ProxyCmp and @Component - * decorators and useExisting (where useExisting refers to the - * class) causes ng-packagr to output multiple component variables - * which breaks treeshaking. - * For example, the following would be generated: - * let IonDatetime = IonDatetime_1 = class IonDatetime extends ValueAccessor { - * Instead, we want only want the class generated: - * class IonDatetime extends ValueAccessor { - */ -import { proxyInputs, proxyMethods, proxyOutputs } from './angular-component-lib/utils'; +import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; const DATETIME_INPUTS = [ 'cancelText', @@ -60,8 +48,11 @@ const DATETIME_INPUTS = [ 'yearValues', ]; -const DATETIME_METHODS = ['confirm', 'reset', 'cancel']; - +@ProxyCmp({ + defineCustomElementFn: defineCustomElement, + inputs: DATETIME_INPUTS, + methods: ['confirm', 'reset', 'cancel'], +}) @Component({ selector: 'ion-datetime', changeDetection: ChangeDetectionStrategy.OnPush, @@ -81,16 +72,8 @@ export class IonDatetime extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); - defineCustomElement(); c.detach(); this.el = r.nativeElement; - /** - * Data-bound input properties are set - * by Angular after the constructor, so - * we need to run the proxy before ngOnInit. - */ - proxyInputs(IonDatetime, DATETIME_INPUTS); - proxyMethods(IonDatetime, DATETIME_METHODS); proxyOutputs(this, this.el, ['ionCancel', 'ionChange', 'ionFocus', 'ionBlur']); } diff --git a/packages/angular/standalone/src/directives/input.ts b/packages/angular/standalone/src/directives/input.ts index 1d1738993f8..1fb55006f7e 100644 --- a/packages/angular/standalone/src/directives/input.ts +++ b/packages/angular/standalone/src/directives/input.ts @@ -17,19 +17,7 @@ import type { } from '@ionic/core/components'; import { defineCustomElement } from '@ionic/core/components/ion-input.js'; -/** - * Value accessor components should not use ProxyCmp - * and should call defineCustomElement and proxyInputs - * manually instead. Using both the @ProxyCmp and @Component - * decorators and useExisting (where useExisting refers to the - * class) causes ng-packagr to output multiple component variables - * which breaks treeshaking. - * For example, the following would be generated: - * let IonInput = IonInput_1 = class IonInput extends ValueAccessor { - * Instead, we want only want the class generated: - * class IonInput extends ValueAccessor { - */ -import { proxyInputs, proxyMethods, proxyOutputs } from './angular-component-lib/utils'; +import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; const INPUT_INPUTS = [ 'accept', @@ -71,8 +59,11 @@ const INPUT_INPUTS = [ 'value', ]; -const INPUT_METHODS = ['setFocus', 'getInputElement']; - +@ProxyCmp({ + defineCustomElementFn: defineCustomElement, + inputs: INPUT_INPUTS, + methods: ['setFocus', 'getInputElement'], +}) @Component({ selector: 'ion-input', changeDetection: ChangeDetectionStrategy.OnPush, @@ -92,16 +83,8 @@ export class IonInput extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); - defineCustomElement(); c.detach(); this.el = r.nativeElement; - /** - * Data-bound input properties are set - * by Angular after the constructor, so - * we need to run the proxy before ngOnInit. - */ - proxyInputs(IonInput, INPUT_INPUTS); - proxyMethods(IonInput, INPUT_METHODS); proxyOutputs(this, this.el, ['ionInput', 'ionChange', 'ionBlur', 'ionFocus']); } diff --git a/packages/angular/standalone/src/directives/radio-group.ts b/packages/angular/standalone/src/directives/radio-group.ts index 5cced80f285..998057a5e34 100644 --- a/packages/angular/standalone/src/directives/radio-group.ts +++ b/packages/angular/standalone/src/directives/radio-group.ts @@ -13,22 +13,14 @@ import { ValueAccessor } from '@ionic/angular/common'; import type { RadioGroupChangeEventDetail, Components } from '@ionic/core/components'; import { defineCustomElement } from '@ionic/core/components/ion-radio-group.js'; -/** - * Value accessor components should not use ProxyCmp - * and should call defineCustomElement and proxyInputs - * manually instead. Using both the @ProxyCmp and @Component - * decorators and useExisting (where useExisting refers to the - * class) causes ng-packagr to output multiple component variables - * which breaks treeshaking. - * For example, the following would be generated: - * let IonRadioGroup = IonRadioGroup_1 = class IonRadioGroup extends ValueAccessor { - * Instead, we want only want the class generated: - * class IonRadioGroup extends ValueAccessor { - */ -import { proxyInputs, proxyOutputs } from './angular-component-lib/utils'; +import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; const RADIO_GROUP_INPUTS = ['allowEmptySelection', 'name', 'value']; +@ProxyCmp({ + defineCustomElementFn: defineCustomElement, + inputs: RADIO_GROUP_INPUTS, +}) @Component({ selector: 'ion-radio-group', changeDetection: ChangeDetectionStrategy.OnPush, @@ -48,15 +40,8 @@ export class IonRadioGroup extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); - defineCustomElement(); c.detach(); this.el = r.nativeElement; - /** - * Data-bound input properties are set - * by Angular after the constructor, so - * we need to run the proxy before ngOnInit. - */ - proxyInputs(IonRadioGroup, RADIO_GROUP_INPUTS); proxyOutputs(this, this.el, ['ionChange']); } diff --git a/packages/angular/standalone/src/directives/radio.ts b/packages/angular/standalone/src/directives/radio.ts index 55cdac06302..9ad32fadf86 100644 --- a/packages/angular/standalone/src/directives/radio.ts +++ b/packages/angular/standalone/src/directives/radio.ts @@ -13,22 +13,14 @@ import { ValueAccessor } from '@ionic/angular/common'; import type { Components } from '@ionic/core/components'; import { defineCustomElement } from '@ionic/core/components/ion-radio.js'; -/** - * Value accessor components should not use ProxyCmp - * and should call defineCustomElement and proxyInputs - * manually instead. Using both the @ProxyCmp and @Component - * decorators and useExisting (where useExisting refers to the - * class) causes ng-packagr to output multiple component variables - * which breaks treeshaking. - * For example, the following would be generated: - * let IonRadio = IonRadio_1 = class IonRadio extends ValueAccessor { - * Instead, we want only want the class generated: - * class IonRadio extends ValueAccessor { - */ -import { proxyInputs, proxyOutputs } from './angular-component-lib/utils'; +import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; const RADIO_INPUTS = ['color', 'disabled', 'justify', 'labelPlacement', 'legacy', 'mode', 'name', 'value']; +@ProxyCmp({ + defineCustomElementFn: defineCustomElement, + inputs: RADIO_INPUTS, +}) @Component({ selector: 'ion-radio', changeDetection: ChangeDetectionStrategy.OnPush, @@ -48,15 +40,8 @@ export class IonRadio extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); - defineCustomElement(); c.detach(); this.el = r.nativeElement; - /** - * Data-bound input properties are set - * by Angular after the constructor, so - * we need to run the proxy before ngOnInit. - */ - proxyInputs(IonRadio, RADIO_INPUTS); proxyOutputs(this, this.el, ['ionFocus', 'ionBlur']); } diff --git a/packages/angular/standalone/src/directives/range.ts b/packages/angular/standalone/src/directives/range.ts index 14aa556dadf..36aa4c93fca 100644 --- a/packages/angular/standalone/src/directives/range.ts +++ b/packages/angular/standalone/src/directives/range.ts @@ -18,19 +18,7 @@ import type { } from '@ionic/core/components'; import { defineCustomElement } from '@ionic/core/components/ion-range.js'; -/** - * Value accessor components should not use ProxyCmp - * and should call defineCustomElement and proxyInputs - * manually instead. Using both the @ProxyCmp and @Component - * decorators and useExisting (where useExisting refers to the - * class) causes ng-packagr to output multiple component variables - * which breaks treeshaking. - * For example, the following would be generated: - * let IonRange = IonRange_1 = class IonRange extends ValueAccessor { - * Instead, we want only want the class generated: - * class IonRange extends ValueAccessor { - */ -import { proxyInputs, proxyOutputs } from './angular-component-lib/utils'; +import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; const RANGE_INPUTS = [ 'activeBarStart', @@ -53,6 +41,10 @@ const RANGE_INPUTS = [ 'value', ]; +@ProxyCmp({ + defineCustomElementFn: defineCustomElement, + inputs: RANGE_INPUTS, +}) @Component({ selector: 'ion-range', changeDetection: ChangeDetectionStrategy.OnPush, @@ -72,15 +64,8 @@ export class IonRange extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); - defineCustomElement(); c.detach(); this.el = r.nativeElement; - /** - * Data-bound input properties are set - * by Angular after the constructor, so - * we need to run the proxy before ngOnInit. - */ - proxyInputs(IonRange, RANGE_INPUTS); proxyOutputs(this, this.el, ['ionChange', 'ionInput', 'ionFocus', 'ionBlur', 'ionKnobMoveStart', 'ionKnobMoveEnd']); } diff --git a/packages/angular/standalone/src/directives/searchbar.ts b/packages/angular/standalone/src/directives/searchbar.ts index 66ac9c3048c..5a4abd6d318 100644 --- a/packages/angular/standalone/src/directives/searchbar.ts +++ b/packages/angular/standalone/src/directives/searchbar.ts @@ -13,19 +13,7 @@ import { ValueAccessor } from '@ionic/angular/common'; import type { SearchbarInputEventDetail, SearchbarChangeEventDetail, Components } from '@ionic/core/components'; import { defineCustomElement } from '@ionic/core/components/ion-searchbar.js'; -/** - * Value accessor components should not use ProxyCmp - * and should call defineCustomElement and proxyInputs - * manually instead. Using both the @ProxyCmp and @Component - * decorators and useExisting (where useExisting refers to the - * class) causes ng-packagr to output multiple component variables - * which breaks treeshaking. - * For example, the following would be generated: - * let IonSearchbar = IonSearchbar_1 = class IonSearchbar extends ValueAccessor { - * Instead, we want only want the class generated: - * class IonSearchbar extends ValueAccessor { - */ -import { proxyInputs, proxyMethods, proxyOutputs } from './angular-component-lib/utils'; +import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; const SEARCHBAR_INPUTS = [ 'animated', @@ -50,8 +38,11 @@ const SEARCHBAR_INPUTS = [ 'value', ]; -const SEARCHBAR_METHODS = ['setFocus', 'getInputElement']; - +@ProxyCmp({ + defineCustomElementFn: defineCustomElement, + inputs: SEARCHBAR_INPUTS, + methods: ['setFocus', 'getInputElement'], +}) @Component({ selector: 'ion-searchbar', changeDetection: ChangeDetectionStrategy.OnPush, @@ -71,16 +62,8 @@ export class IonSearchbar extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); - defineCustomElement(); c.detach(); this.el = r.nativeElement; - /** - * Data-bound input properties are set - * by Angular after the constructor, so - * we need to run the proxy before ngOnInit. - */ - proxyInputs(IonSearchbar, SEARCHBAR_INPUTS); - proxyMethods(IonSearchbar, SEARCHBAR_METHODS); proxyOutputs(this, this.el, ['ionInput', 'ionChange', 'ionCancel', 'ionClear', 'ionBlur', 'ionFocus']); } diff --git a/packages/angular/standalone/src/directives/segment.ts b/packages/angular/standalone/src/directives/segment.ts index 8fd01dfcd05..760b990d5e5 100644 --- a/packages/angular/standalone/src/directives/segment.ts +++ b/packages/angular/standalone/src/directives/segment.ts @@ -13,22 +13,14 @@ import { ValueAccessor } from '@ionic/angular/common'; import type { SegmentChangeEventDetail, Components } from '@ionic/core/components'; import { defineCustomElement } from '@ionic/core/components/ion-segment.js'; -/** - * Value accessor components should not use ProxyCmp - * and should call defineCustomElement and proxyInputs - * manually instead. Using both the @ProxyCmp and @Component - * decorators and useExisting (where useExisting refers to the - * class) causes ng-packagr to output multiple component variables - * which breaks treeshaking. - * For example, the following would be generated: - * let IonSegment = IonSegment_1 = class IonSegment extends ValueAccessor { - * Instead, we want only want the class generated: - * class IonSegment extends ValueAccessor { - */ -import { proxyInputs, proxyOutputs } from './angular-component-lib/utils'; +import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; const SEGMENT_INPUTS = ['color', 'disabled', 'mode', 'scrollable', 'selectOnFocus', 'swipeGesture', 'value']; +@ProxyCmp({ + defineCustomElementFn: defineCustomElement, + inputs: SEGMENT_INPUTS, +}) @Component({ selector: 'ion-segment', changeDetection: ChangeDetectionStrategy.OnPush, @@ -48,15 +40,8 @@ export class IonSegment extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); - defineCustomElement(); c.detach(); this.el = r.nativeElement; - /** - * Data-bound input properties are set - * by Angular after the constructor, so - * we need to run the proxy before ngOnInit. - */ - proxyInputs(IonSegment, SEGMENT_INPUTS); proxyOutputs(this, this.el, ['ionChange']); } diff --git a/packages/angular/standalone/src/directives/select.ts b/packages/angular/standalone/src/directives/select.ts index 6a896820d5e..f0d19ce078e 100644 --- a/packages/angular/standalone/src/directives/select.ts +++ b/packages/angular/standalone/src/directives/select.ts @@ -13,19 +13,7 @@ import { ValueAccessor } from '@ionic/angular/common'; import type { SelectChangeEventDetail, Components } from '@ionic/core/components'; import { defineCustomElement } from '@ionic/core/components/ion-select.js'; -/** - * Value accessor components should not use ProxyCmp - * and should call defineCustomElement and proxyInputs - * manually instead. Using both the @ProxyCmp and @Component - * decorators and useExisting (where useExisting refers to the - * class) causes ng-packagr to output multiple component variables - * which breaks treeshaking. - * For example, the following would be generated: - * let IonSelect = IonSelect_1 = class IonSelect extends ValueAccessor { - * Instead, we want only want the class generated: - * class IonSelect extends ValueAccessor { - */ -import { proxyInputs, proxyMethods, proxyOutputs } from './angular-component-lib/utils'; +import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; const SELECT_INPUTS = [ 'cancelText', @@ -51,8 +39,11 @@ const SELECT_INPUTS = [ 'value', ]; -const SELECT_METHODS = ['open']; - +@ProxyCmp({ + defineCustomElementFn: defineCustomElement, + inputs: SELECT_INPUTS, + methods: ['open'], +}) @Component({ selector: 'ion-select', changeDetection: ChangeDetectionStrategy.OnPush, @@ -72,16 +63,8 @@ export class IonSelect extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); - defineCustomElement(); c.detach(); this.el = r.nativeElement; - /** - * Data-bound input properties are set - * by Angular after the constructor, so - * we need to run the proxy before ngOnInit. - */ - proxyInputs(IonSelect, SELECT_INPUTS); - proxyMethods(IonSelect, SELECT_METHODS); proxyOutputs(this, this.el, ['ionChange', 'ionCancel', 'ionDismiss', 'ionFocus', 'ionBlur']); } diff --git a/packages/angular/standalone/src/directives/textarea.ts b/packages/angular/standalone/src/directives/textarea.ts index 9c590d1f87c..75239632320 100644 --- a/packages/angular/standalone/src/directives/textarea.ts +++ b/packages/angular/standalone/src/directives/textarea.ts @@ -13,19 +13,7 @@ import { ValueAccessor } from '@ionic/angular/common'; import type { TextareaChangeEventDetail, TextareaInputEventDetail, Components } from '@ionic/core/components'; import { defineCustomElement } from '@ionic/core/components/ion-textarea.js'; -/** - * Value accessor components should not use ProxyCmp - * and should call defineCustomElement and proxyInputs - * manually instead. Using both the @ProxyCmp and @Component - * decorators and useExisting (where useExisting refers to the - * class) causes ng-packagr to output multiple component variables - * which breaks treeshaking. - * For example, the following would be generated: - * let IonTextarea = IonTextarea_1 = class IonTextarea extends ValueAccessor { - * Instead, we want only want the class generated: - * class IonTextarea extends ValueAccessor { - */ -import { proxyInputs, proxyMethods, proxyOutputs } from './angular-component-lib/utils'; +import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; const TEXTAREA_INPUTS = [ 'autoGrow', @@ -60,8 +48,11 @@ const TEXTAREA_INPUTS = [ 'wrap', ]; -const TEXTAREA_METHODS = ['setFocus', 'getInputElement']; - +@ProxyCmp({ + defineCustomElementFn: defineCustomElement, + inputs: TEXTAREA_INPUTS, + methods: ['setFocus', 'getInputElement'], +}) @Component({ selector: 'ion-textarea', changeDetection: ChangeDetectionStrategy.OnPush, @@ -81,16 +72,8 @@ export class IonTextarea extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); - defineCustomElement(); c.detach(); this.el = r.nativeElement; - /** - * Data-bound input properties are set - * by Angular after the constructor, so - * we need to run the proxy before ngOnInit. - */ - proxyInputs(IonTextarea, TEXTAREA_INPUTS); - proxyMethods(IonTextarea, TEXTAREA_METHODS); proxyOutputs(this, this.el, ['ionChange', 'ionInput', 'ionBlur', 'ionFocus']); } diff --git a/packages/angular/standalone/src/directives/toggle.ts b/packages/angular/standalone/src/directives/toggle.ts index d9f2787cfd9..e1ece5f856e 100644 --- a/packages/angular/standalone/src/directives/toggle.ts +++ b/packages/angular/standalone/src/directives/toggle.ts @@ -13,19 +13,7 @@ import { ValueAccessor, setIonicClasses } from '@ionic/angular/common'; import type { ToggleChangeEventDetail, Components } from '@ionic/core/components'; import { defineCustomElement } from '@ionic/core/components/ion-toggle.js'; -/** - * Value accessor components should not use ProxyCmp - * and should call defineCustomElement and proxyInputs - * manually instead. Using both the @ProxyCmp and @Component - * decorators and useExisting (where useExisting refers to the - * class) causes ng-packagr to output multiple component variables - * which breaks treeshaking. - * For example, the following would be generated: - * let IonToggle = IonToggle_1 = class IonToggle extends ValueAccessor { - * Instead, we want only want the class generated: - * class IonToggle extends ValueAccessor { - */ -import { proxyInputs, proxyOutputs } from './angular-component-lib/utils'; +import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; const TOGGLE_INPUTS = [ 'checked', @@ -40,6 +28,10 @@ const TOGGLE_INPUTS = [ 'value', ]; +@ProxyCmp({ + defineCustomElementFn: defineCustomElement, + inputs: TOGGLE_INPUTS, +}) @Component({ selector: 'ion-toggle', changeDetection: ChangeDetectionStrategy.OnPush, @@ -59,15 +51,8 @@ export class IonToggle extends ValueAccessor { protected el: HTMLElement; constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { super(injector, r); - defineCustomElement(); c.detach(); this.el = r.nativeElement; - /** - * Data-bound input properties are set - * by Angular after the constructor, so - * we need to run the proxy before ngOnInit. - */ - proxyInputs(IonToggle, TOGGLE_INPUTS); proxyOutputs(this, this.el, ['ionChange', 'ionFocus', 'ionBlur']); } diff --git a/packages/angular/test/base/e2e/src/standalone/value-accessors.spec.ts b/packages/angular/test/base/e2e/src/standalone/value-accessors.spec.ts index 1e82274c801..a8e1c36e90c 100644 --- a/packages/angular/test/base/e2e/src/standalone/value-accessors.spec.ts +++ b/packages/angular/test/base/e2e/src/standalone/value-accessors.spec.ts @@ -14,18 +14,6 @@ describe('Value Accessors', () => { cy.get('ion-checkbox').should('have.class', 'ion-dirty'); cy.get('ion-checkbox').should('have.class', 'ion-valid'); }); - - it('should proxy inputs on load', () => { - cy.get('ion-checkbox').should('have.prop', 'color', 'danger'); - }); - }); - - describe('Datetime', () => { - beforeEach(() => cy.visit('/standalone/value-accessors/datetime')); - - it('should proxy inputs on load', () => { - cy.get('ion-datetime').should('have.prop', 'color', 'danger'); - }); }); describe('Input', () => { @@ -60,10 +48,6 @@ describe('Value Accessors', () => { cy.get('ion-input[formControlName="inputNumber"]').should('have.class', 'ion-valid'); }); - - it('should proxy inputs on load', () => { - cy.get('ion-input').first().should('have.prop', 'color', 'danger'); - }); }); describe('Radio Group', () => { @@ -79,21 +63,8 @@ describe('Value Accessors', () => { cy.get('ion-radio-group').should('have.class', 'ion-dirty'); cy.get('ion-radio-group').should('have.class', 'ion-valid'); }); - - it('should proxy inputs on load', () => { - cy.get('ion-radio').first().should('have.prop', 'color', 'danger'); - }); - }); - - describe('Range', () => { - beforeEach(() => cy.visit('/standalone/value-accessors/range')); - - it('should proxy inputs on load', () => { - cy.get('ion-range').should('have.prop', 'color', 'danger'); - }); }); - describe('Searchbar', () => { beforeEach(() => cy.visit('/standalone/value-accessors/searchbar')); @@ -109,10 +80,6 @@ describe('Value Accessors', () => { cy.get('ion-searchbar').should('have.class', 'ion-dirty'); cy.get('ion-searchbar').should('have.class', 'ion-valid'); }); - - it('should proxy inputs on load', () => { - cy.get('ion-searchbar').should('have.prop', 'color', 'danger'); - }); }); describe('Segment', () => { @@ -128,32 +95,6 @@ describe('Value Accessors', () => { cy.get('ion-segment').should('have.class', 'ion-dirty'); cy.get('ion-segment').should('have.class', 'ion-valid'); }); - - it('should proxy inputs on load', () => { - cy.get('ion-segment').should('have.prop', 'color', 'danger'); - }); - }); - - describe('Select', () => { - beforeEach(() => cy.visit('/standalone/value-accessors/select')); - - it('should update the form value', () => { - cy.get('#formValue').should('have.text', JSON.stringify({ select: 'bananas' }, null, 2)); - cy.get('ion-select').should('have.class', 'ion-pristine'); - - cy.get('ion-select').click(); - cy.get('ion-popover').should('be.visible'); - - cy.get('ion-popover ion-radio-group ion-radio').first().click(); - - cy.get('#formValue').should('have.text', JSON.stringify({ select: 'apples' }, null, 2)); - cy.get('ion-select').should('have.class', 'ion-dirty'); - cy.get('ion-select').should('have.class', 'ion-valid'); - }); - - it('should proxy inputs on load', () => { - cy.get('ion-select').should('have.prop', 'color', 'danger'); - }); }); describe('Textarea', () => { @@ -171,10 +112,6 @@ describe('Value Accessors', () => { cy.get('ion-textarea').should('have.class', 'ion-dirty'); cy.get('ion-textarea').should('have.class', 'ion-valid'); }); - - it('should proxy inputs on load', () => { - cy.get('ion-textarea').should('have.prop', 'color', 'danger'); - }); }); describe('Toggle', () => { @@ -190,10 +127,6 @@ describe('Value Accessors', () => { cy.get('ion-toggle').should('have.class', 'ion-dirty'); cy.get('ion-toggle').should('have.class', 'ion-valid'); }); - - it('should proxy inputs on load', () => { - cy.get('ion-toggle').should('have.prop', 'color', 'danger'); - }); }); }); diff --git a/packages/angular/test/base/src/app/standalone/app-standalone/app.routes.ts b/packages/angular/test/base/src/app/standalone/app-standalone/app.routes.ts index 3e2499ca112..d5618a3ce89 100644 --- a/packages/angular/test/base/src/app/standalone/app-standalone/app.routes.ts +++ b/packages/angular/test/base/src/app/standalone/app-standalone/app.routes.ts @@ -37,7 +37,6 @@ export const routes: Routes = [ { path: 'range', loadComponent: () => import('../value-accessors/range/range.component').then(c => c.RangeComponent) }, { path: 'searchbar', loadComponent: () => import('../value-accessors/searchbar/searchbar.component').then(c => c.SearchbarComponent) }, { path: 'segment', loadComponent: () => import('../value-accessors/segment/segment.component').then(c => c.SegmentComponent) }, - { path: 'select', loadComponent: () => import('../value-accessors/select/select.component').then(c => c.SelectComponent) }, { path: 'textarea', loadComponent: () => import('../value-accessors/textarea/textarea.component').then(c => c.TextareaComponent) }, { path: 'toggle', loadComponent: () => import('../value-accessors/toggle/toggle.component').then(c => c.ToggleComponent) }, { path: '**', redirectTo: 'checkbox' } diff --git a/packages/angular/test/base/src/app/standalone/value-accessors/checkbox/checkbox.component.html b/packages/angular/test/base/src/app/standalone/value-accessors/checkbox/checkbox.component.html index b3d621b0aeb..2921e06b917 100644 --- a/packages/angular/test/base/src/app/standalone/value-accessors/checkbox/checkbox.component.html +++ b/packages/angular/test/base/src/app/standalone/value-accessors/checkbox/checkbox.component.html @@ -6,6 +6,6 @@

IonCheckbox Value Accessors

- + diff --git a/packages/angular/test/base/src/app/standalone/value-accessors/datetime/datetime.component.html b/packages/angular/test/base/src/app/standalone/value-accessors/datetime/datetime.component.html index 6d682257c88..22c36339717 100644 --- a/packages/angular/test/base/src/app/standalone/value-accessors/datetime/datetime.component.html +++ b/packages/angular/test/base/src/app/standalone/value-accessors/datetime/datetime.component.html @@ -6,6 +6,6 @@

IonDatetime Value Accessors

- + diff --git a/packages/angular/test/base/src/app/standalone/value-accessors/input/input.component.html b/packages/angular/test/base/src/app/standalone/value-accessors/input/input.component.html index aa9a2feeff6..e63235cea5a 100644 --- a/packages/angular/test/base/src/app/standalone/value-accessors/input/input.component.html +++ b/packages/angular/test/base/src/app/standalone/value-accessors/input/input.component.html @@ -5,7 +5,7 @@

IonInput Value Accessors

- + diff --git a/packages/angular/test/base/src/app/standalone/value-accessors/radio-group/radio-group.component.html b/packages/angular/test/base/src/app/standalone/value-accessors/radio-group/radio-group.component.html index 274dfd24788..a511dbbbe50 100644 --- a/packages/angular/test/base/src/app/standalone/value-accessors/radio-group/radio-group.component.html +++ b/packages/angular/test/base/src/app/standalone/value-accessors/radio-group/radio-group.component.html @@ -7,7 +7,7 @@

IonRadioGroup Value Accessors

- One + One Two diff --git a/packages/angular/test/base/src/app/standalone/value-accessors/range/range.component.html b/packages/angular/test/base/src/app/standalone/value-accessors/range/range.component.html index 969f4b13c7f..9a496fbcd3c 100644 --- a/packages/angular/test/base/src/app/standalone/value-accessors/range/range.component.html +++ b/packages/angular/test/base/src/app/standalone/value-accessors/range/range.component.html @@ -4,6 +4,6 @@

IonRange Value Accessors

This test checks the form integrations with ion-range to make sure values are correctly assigned to the form group.

- + diff --git a/packages/angular/test/base/src/app/standalone/value-accessors/searchbar/searchbar.component.html b/packages/angular/test/base/src/app/standalone/value-accessors/searchbar/searchbar.component.html index c667a787d24..9a6137c65ba 100644 --- a/packages/angular/test/base/src/app/standalone/value-accessors/searchbar/searchbar.component.html +++ b/packages/angular/test/base/src/app/standalone/value-accessors/searchbar/searchbar.component.html @@ -5,6 +5,6 @@

IonSearchbar Value Accessors

group.

- + diff --git a/packages/angular/test/base/src/app/standalone/value-accessors/segment/segment.component.html b/packages/angular/test/base/src/app/standalone/value-accessors/segment/segment.component.html index fca9dba8bcc..98016fcde68 100644 --- a/packages/angular/test/base/src/app/standalone/value-accessors/segment/segment.component.html +++ b/packages/angular/test/base/src/app/standalone/value-accessors/segment/segment.component.html @@ -6,7 +6,7 @@

IonSegment Value Accessors

- + Paid diff --git a/packages/angular/test/base/src/app/standalone/value-accessors/select/select.component.html b/packages/angular/test/base/src/app/standalone/value-accessors/select/select.component.html deleted file mode 100644 index 28dbda038da..00000000000 --- a/packages/angular/test/base/src/app/standalone/value-accessors/select/select.component.html +++ /dev/null @@ -1,14 +0,0 @@ -
-

IonSelect Value Accessors

-

- This test checks the form integrations with ion-select to make sure values are correctly assigned to the form - group. -

- - - - Apples - Bananas - - -
diff --git a/packages/angular/test/base/src/app/standalone/value-accessors/select/select.component.ts b/packages/angular/test/base/src/app/standalone/value-accessors/select/select.component.ts deleted file mode 100644 index 35246438f5f..00000000000 --- a/packages/angular/test/base/src/app/standalone/value-accessors/select/select.component.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Component } from "@angular/core"; -import { FormBuilder, FormsModule, ReactiveFormsModule, Validators } from "@angular/forms"; -import { IonSelect, IonSelectOption } from "@ionic/angular/standalone"; -import { ValueAccessorTestComponent } from "../value-accessor-test/value-accessor-test.component"; - -@Component({ - selector: 'app-select', - templateUrl: 'select.component.html', - standalone: true, - imports: [ - IonSelect, - IonSelectOption, - ReactiveFormsModule, - FormsModule, - ValueAccessorTestComponent - ] -}) -export class SelectComponent { - - form = this.fb.group({ - select: ['bananas', Validators.required], - }); - - constructor(private fb: FormBuilder) { } - -} diff --git a/packages/angular/test/base/src/app/standalone/value-accessors/textarea/textarea.component.html b/packages/angular/test/base/src/app/standalone/value-accessors/textarea/textarea.component.html index 05ab51817a1..678d42d391a 100644 --- a/packages/angular/test/base/src/app/standalone/value-accessors/textarea/textarea.component.html +++ b/packages/angular/test/base/src/app/standalone/value-accessors/textarea/textarea.component.html @@ -6,6 +6,6 @@

IonTextarea Value Accessors

- + diff --git a/packages/angular/test/base/src/app/standalone/value-accessors/toggle/toggle.component.html b/packages/angular/test/base/src/app/standalone/value-accessors/toggle/toggle.component.html index b7d74781c55..08888059f99 100644 --- a/packages/angular/test/base/src/app/standalone/value-accessors/toggle/toggle.component.html +++ b/packages/angular/test/base/src/app/standalone/value-accessors/toggle/toggle.component.html @@ -5,6 +5,6 @@

IonToggle Value Accessors

- + From 2de705ecb04d9eb7a4e247ad65e97f2235f4236d Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Mon, 30 Oct 2023 15:20:42 -0400 Subject: [PATCH 3/6] move provider to object to avoid ng-package issue --- .../angular/standalone/src/directives/checkbox.ts | 15 ++++++++------- .../angular/standalone/src/directives/datetime.ts | 15 ++++++++------- .../angular/standalone/src/directives/input.ts | 15 ++++++++------- .../standalone/src/directives/radio-group.ts | 15 ++++++++------- .../angular/standalone/src/directives/radio.ts | 15 ++++++++------- .../angular/standalone/src/directives/range.ts | 15 ++++++++------- .../standalone/src/directives/searchbar.ts | 15 ++++++++------- .../angular/standalone/src/directives/segment.ts | 15 ++++++++------- .../angular/standalone/src/directives/select.ts | 15 ++++++++------- .../angular/standalone/src/directives/textarea.ts | 15 ++++++++------- .../angular/standalone/src/directives/toggle.ts | 15 ++++++++------- 11 files changed, 88 insertions(+), 77 deletions(-) diff --git a/packages/angular/standalone/src/directives/checkbox.ts b/packages/angular/standalone/src/directives/checkbox.ts index 26f139f379b..9b20c5a8e60 100644 --- a/packages/angular/standalone/src/directives/checkbox.ts +++ b/packages/angular/standalone/src/directives/checkbox.ts @@ -7,6 +7,7 @@ import { HostListener, Injector, NgZone, + forwardRef, } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor, setIonicClasses } from '@ionic/angular/common'; @@ -28,6 +29,12 @@ const CHECKBOX_INPUTS = [ 'value', ]; +const accessorProvider = { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => IonCheckbox), + multi: true, +}; + @ProxyCmp({ defineCustomElementFn: defineCustomElement, inputs: CHECKBOX_INPUTS, @@ -38,13 +45,7 @@ const CHECKBOX_INPUTS = [ template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property inputs: CHECKBOX_INPUTS, - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: IonCheckbox, - multi: true, - }, - ], + providers: [accessorProvider], standalone: true, }) export class IonCheckbox extends ValueAccessor { diff --git a/packages/angular/standalone/src/directives/datetime.ts b/packages/angular/standalone/src/directives/datetime.ts index 57068f71b97..0ea911e35a7 100644 --- a/packages/angular/standalone/src/directives/datetime.ts +++ b/packages/angular/standalone/src/directives/datetime.ts @@ -7,6 +7,7 @@ import { HostListener, Injector, NgZone, + forwardRef, } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor } from '@ionic/angular/common'; @@ -48,6 +49,12 @@ const DATETIME_INPUTS = [ 'yearValues', ]; +const accessorProvider = { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => IonDatetime), + multi: true, +}; + @ProxyCmp({ defineCustomElementFn: defineCustomElement, inputs: DATETIME_INPUTS, @@ -59,13 +66,7 @@ const DATETIME_INPUTS = [ template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property inputs: DATETIME_INPUTS, - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: IonDatetime, - multi: true, - }, - ], + providers: [accessorProvider], standalone: true, }) export class IonDatetime extends ValueAccessor { diff --git a/packages/angular/standalone/src/directives/input.ts b/packages/angular/standalone/src/directives/input.ts index 1fb55006f7e..cb6643aad7d 100644 --- a/packages/angular/standalone/src/directives/input.ts +++ b/packages/angular/standalone/src/directives/input.ts @@ -7,6 +7,7 @@ import { HostListener, Injector, NgZone, + forwardRef, } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor } from '@ionic/angular/common'; @@ -59,6 +60,12 @@ const INPUT_INPUTS = [ 'value', ]; +const accessorProvider = { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => IonInput), + multi: true, +}; + @ProxyCmp({ defineCustomElementFn: defineCustomElement, inputs: INPUT_INPUTS, @@ -70,13 +77,7 @@ const INPUT_INPUTS = [ template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property inputs: INPUT_INPUTS, - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: IonInput, - multi: true, - }, - ], + providers: [accessorProvider], standalone: true, }) export class IonInput extends ValueAccessor { diff --git a/packages/angular/standalone/src/directives/radio-group.ts b/packages/angular/standalone/src/directives/radio-group.ts index 998057a5e34..a26002a191f 100644 --- a/packages/angular/standalone/src/directives/radio-group.ts +++ b/packages/angular/standalone/src/directives/radio-group.ts @@ -7,6 +7,7 @@ import { HostListener, Injector, NgZone, + forwardRef, } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor } from '@ionic/angular/common'; @@ -17,6 +18,12 @@ import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; const RADIO_GROUP_INPUTS = ['allowEmptySelection', 'name', 'value']; +const accessorProvider = { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => IonRadioGroup), + multi: true, +}; + @ProxyCmp({ defineCustomElementFn: defineCustomElement, inputs: RADIO_GROUP_INPUTS, @@ -27,13 +34,7 @@ const RADIO_GROUP_INPUTS = ['allowEmptySelection', 'name', 'value']; template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property inputs: RADIO_GROUP_INPUTS, - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: IonRadioGroup, - multi: true, - }, - ], + providers: [accessorProvider], standalone: true, }) export class IonRadioGroup extends ValueAccessor { diff --git a/packages/angular/standalone/src/directives/radio.ts b/packages/angular/standalone/src/directives/radio.ts index 9ad32fadf86..bfdf8720a77 100644 --- a/packages/angular/standalone/src/directives/radio.ts +++ b/packages/angular/standalone/src/directives/radio.ts @@ -7,6 +7,7 @@ import { HostListener, Injector, NgZone, + forwardRef, } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor } from '@ionic/angular/common'; @@ -17,6 +18,12 @@ import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; const RADIO_INPUTS = ['color', 'disabled', 'justify', 'labelPlacement', 'legacy', 'mode', 'name', 'value']; +const accessorProvider = { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => IonRadio), + multi: true, +}; + @ProxyCmp({ defineCustomElementFn: defineCustomElement, inputs: RADIO_INPUTS, @@ -27,13 +34,7 @@ const RADIO_INPUTS = ['color', 'disabled', 'justify', 'labelPlacement', 'legacy' template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property inputs: RADIO_INPUTS, - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: IonRadio, - multi: true, - }, - ], + providers: [accessorProvider], standalone: true, }) export class IonRadio extends ValueAccessor { diff --git a/packages/angular/standalone/src/directives/range.ts b/packages/angular/standalone/src/directives/range.ts index 36aa4c93fca..c916d29721e 100644 --- a/packages/angular/standalone/src/directives/range.ts +++ b/packages/angular/standalone/src/directives/range.ts @@ -7,6 +7,7 @@ import { HostListener, Injector, NgZone, + forwardRef, } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor } from '@ionic/angular/common'; @@ -41,6 +42,12 @@ const RANGE_INPUTS = [ 'value', ]; +const accessorProvider = { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => IonRange), + multi: true, +}; + @ProxyCmp({ defineCustomElementFn: defineCustomElement, inputs: RANGE_INPUTS, @@ -51,13 +58,7 @@ const RANGE_INPUTS = [ template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property inputs: RANGE_INPUTS, - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: IonRange, - multi: true, - }, - ], + providers: [accessorProvider], standalone: true, }) export class IonRange extends ValueAccessor { diff --git a/packages/angular/standalone/src/directives/searchbar.ts b/packages/angular/standalone/src/directives/searchbar.ts index 5a4abd6d318..17365d1c9db 100644 --- a/packages/angular/standalone/src/directives/searchbar.ts +++ b/packages/angular/standalone/src/directives/searchbar.ts @@ -7,6 +7,7 @@ import { HostListener, Injector, NgZone, + forwardRef, } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor } from '@ionic/angular/common'; @@ -38,6 +39,12 @@ const SEARCHBAR_INPUTS = [ 'value', ]; +const accessorProvider = { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => IonSearchbar), + multi: true, +}; + @ProxyCmp({ defineCustomElementFn: defineCustomElement, inputs: SEARCHBAR_INPUTS, @@ -49,13 +56,7 @@ const SEARCHBAR_INPUTS = [ template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property inputs: SEARCHBAR_INPUTS, - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: IonSearchbar, - multi: true, - }, - ], + providers: [accessorProvider], standalone: true, }) export class IonSearchbar extends ValueAccessor { diff --git a/packages/angular/standalone/src/directives/segment.ts b/packages/angular/standalone/src/directives/segment.ts index 760b990d5e5..7bdfe0e2e30 100644 --- a/packages/angular/standalone/src/directives/segment.ts +++ b/packages/angular/standalone/src/directives/segment.ts @@ -7,6 +7,7 @@ import { HostListener, Injector, NgZone, + forwardRef, } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor } from '@ionic/angular/common'; @@ -17,6 +18,12 @@ import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; const SEGMENT_INPUTS = ['color', 'disabled', 'mode', 'scrollable', 'selectOnFocus', 'swipeGesture', 'value']; +const accessorProvider = { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => IonSegment), + multi: true, +}; + @ProxyCmp({ defineCustomElementFn: defineCustomElement, inputs: SEGMENT_INPUTS, @@ -27,13 +34,7 @@ const SEGMENT_INPUTS = ['color', 'disabled', 'mode', 'scrollable', 'selectOnFocu template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property inputs: SEGMENT_INPUTS, - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: IonSegment, - multi: true, - }, - ], + providers: [accessorProvider], standalone: true, }) export class IonSegment extends ValueAccessor { diff --git a/packages/angular/standalone/src/directives/select.ts b/packages/angular/standalone/src/directives/select.ts index f0d19ce078e..75915cf28b5 100644 --- a/packages/angular/standalone/src/directives/select.ts +++ b/packages/angular/standalone/src/directives/select.ts @@ -7,6 +7,7 @@ import { HostListener, Injector, NgZone, + forwardRef, } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor } from '@ionic/angular/common'; @@ -39,6 +40,12 @@ const SELECT_INPUTS = [ 'value', ]; +const accessorProvider = { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => IonSelect), + multi: true, +}; + @ProxyCmp({ defineCustomElementFn: defineCustomElement, inputs: SELECT_INPUTS, @@ -50,13 +57,7 @@ const SELECT_INPUTS = [ template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property inputs: SELECT_INPUTS, - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: IonSelect, - multi: true, - }, - ], + providers: [accessorProvider], standalone: true, }) export class IonSelect extends ValueAccessor { diff --git a/packages/angular/standalone/src/directives/textarea.ts b/packages/angular/standalone/src/directives/textarea.ts index 75239632320..f8544fbdd69 100644 --- a/packages/angular/standalone/src/directives/textarea.ts +++ b/packages/angular/standalone/src/directives/textarea.ts @@ -7,6 +7,7 @@ import { HostListener, Injector, NgZone, + forwardRef, } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor } from '@ionic/angular/common'; @@ -48,6 +49,12 @@ const TEXTAREA_INPUTS = [ 'wrap', ]; +const accessorProvider = { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => IonTextarea), + multi: true, +}; + @ProxyCmp({ defineCustomElementFn: defineCustomElement, inputs: TEXTAREA_INPUTS, @@ -59,13 +66,7 @@ const TEXTAREA_INPUTS = [ template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property inputs: TEXTAREA_INPUTS, - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: IonTextarea, - multi: true, - }, - ], + providers: [accessorProvider], standalone: true, }) export class IonTextarea extends ValueAccessor { diff --git a/packages/angular/standalone/src/directives/toggle.ts b/packages/angular/standalone/src/directives/toggle.ts index e1ece5f856e..9ebb874b86b 100644 --- a/packages/angular/standalone/src/directives/toggle.ts +++ b/packages/angular/standalone/src/directives/toggle.ts @@ -7,6 +7,7 @@ import { HostListener, Injector, NgZone, + forwardRef, } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { ValueAccessor, setIonicClasses } from '@ionic/angular/common'; @@ -28,6 +29,12 @@ const TOGGLE_INPUTS = [ 'value', ]; +const accessorProvider = { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => IonToggle), + multi: true, +}; + @ProxyCmp({ defineCustomElementFn: defineCustomElement, inputs: TOGGLE_INPUTS, @@ -38,13 +45,7 @@ const TOGGLE_INPUTS = [ template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property inputs: TOGGLE_INPUTS, - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: IonToggle, - multi: true, - }, - ], + providers: [accessorProvider], standalone: true, }) export class IonToggle extends ValueAccessor { From 235faf8c2334402b622328403c204b4750da6f02 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Mon, 30 Oct 2023 15:25:56 -0400 Subject: [PATCH 4/6] keep new select test --- .../src/standalone/value-accessors.spec.ts | 18 +++++++++++++ .../standalone/app-standalone/app.routes.ts | 1 + .../select/select.component.html | 14 ++++++++++ .../select/select.component.ts | 26 +++++++++++++++++++ 4 files changed, 59 insertions(+) create mode 100644 packages/angular/test/base/src/app/standalone/value-accessors/select/select.component.html create mode 100644 packages/angular/test/base/src/app/standalone/value-accessors/select/select.component.ts diff --git a/packages/angular/test/base/e2e/src/standalone/value-accessors.spec.ts b/packages/angular/test/base/e2e/src/standalone/value-accessors.spec.ts index a8e1c36e90c..ab03da596a1 100644 --- a/packages/angular/test/base/e2e/src/standalone/value-accessors.spec.ts +++ b/packages/angular/test/base/e2e/src/standalone/value-accessors.spec.ts @@ -97,6 +97,24 @@ describe('Value Accessors', () => { }); }); + describe('Select', () => { + beforeEach(() => cy.visit('/standalone/value-accessors/select')); + + it('should update the form value', () => { + cy.get('#formValue').should('have.text', JSON.stringify({ select: 'bananas' }, null, 2)); + cy.get('ion-select').should('have.class', 'ion-pristine'); + + cy.get('ion-select').click(); + cy.get('ion-popover').should('be.visible'); + + cy.get('ion-popover ion-radio-group ion-radio').first().click(); + + cy.get('#formValue').should('have.text', JSON.stringify({ select: 'apples' }, null, 2)); + cy.get('ion-select').should('have.class', 'ion-dirty'); + cy.get('ion-select').should('have.class', 'ion-valid'); + }); + }); + describe('Textarea', () => { beforeEach(() => cy.visit('/standalone/value-accessors/textarea')); diff --git a/packages/angular/test/base/src/app/standalone/app-standalone/app.routes.ts b/packages/angular/test/base/src/app/standalone/app-standalone/app.routes.ts index d5618a3ce89..3e2499ca112 100644 --- a/packages/angular/test/base/src/app/standalone/app-standalone/app.routes.ts +++ b/packages/angular/test/base/src/app/standalone/app-standalone/app.routes.ts @@ -37,6 +37,7 @@ export const routes: Routes = [ { path: 'range', loadComponent: () => import('../value-accessors/range/range.component').then(c => c.RangeComponent) }, { path: 'searchbar', loadComponent: () => import('../value-accessors/searchbar/searchbar.component').then(c => c.SearchbarComponent) }, { path: 'segment', loadComponent: () => import('../value-accessors/segment/segment.component').then(c => c.SegmentComponent) }, + { path: 'select', loadComponent: () => import('../value-accessors/select/select.component').then(c => c.SelectComponent) }, { path: 'textarea', loadComponent: () => import('../value-accessors/textarea/textarea.component').then(c => c.TextareaComponent) }, { path: 'toggle', loadComponent: () => import('../value-accessors/toggle/toggle.component').then(c => c.ToggleComponent) }, { path: '**', redirectTo: 'checkbox' } diff --git a/packages/angular/test/base/src/app/standalone/value-accessors/select/select.component.html b/packages/angular/test/base/src/app/standalone/value-accessors/select/select.component.html new file mode 100644 index 00000000000..28dbda038da --- /dev/null +++ b/packages/angular/test/base/src/app/standalone/value-accessors/select/select.component.html @@ -0,0 +1,14 @@ +
+

IonSelect Value Accessors

+

+ This test checks the form integrations with ion-select to make sure values are correctly assigned to the form + group. +

+ + + + Apples + Bananas + + +
diff --git a/packages/angular/test/base/src/app/standalone/value-accessors/select/select.component.ts b/packages/angular/test/base/src/app/standalone/value-accessors/select/select.component.ts new file mode 100644 index 00000000000..35246438f5f --- /dev/null +++ b/packages/angular/test/base/src/app/standalone/value-accessors/select/select.component.ts @@ -0,0 +1,26 @@ +import { Component } from "@angular/core"; +import { FormBuilder, FormsModule, ReactiveFormsModule, Validators } from "@angular/forms"; +import { IonSelect, IonSelectOption } from "@ionic/angular/standalone"; +import { ValueAccessorTestComponent } from "../value-accessor-test/value-accessor-test.component"; + +@Component({ + selector: 'app-select', + templateUrl: 'select.component.html', + standalone: true, + imports: [ + IonSelect, + IonSelectOption, + ReactiveFormsModule, + FormsModule, + ValueAccessorTestComponent + ] +}) +export class SelectComponent { + + form = this.fb.group({ + select: ['bananas', Validators.required], + }); + + constructor(private fb: FormBuilder) { } + +} From 16c968ec4999f575e759324750cd991817793794 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Mon, 30 Oct 2023 15:28:17 -0400 Subject: [PATCH 5/6] add comments --- packages/angular/standalone/src/directives/checkbox.ts | 8 ++++++++ packages/angular/standalone/src/directives/datetime.ts | 8 ++++++++ packages/angular/standalone/src/directives/input.ts | 8 ++++++++ packages/angular/standalone/src/directives/radio-group.ts | 8 ++++++++ packages/angular/standalone/src/directives/radio.ts | 8 ++++++++ packages/angular/standalone/src/directives/range.ts | 8 ++++++++ packages/angular/standalone/src/directives/searchbar.ts | 8 ++++++++ packages/angular/standalone/src/directives/segment.ts | 8 ++++++++ packages/angular/standalone/src/directives/select.ts | 8 ++++++++ packages/angular/standalone/src/directives/textarea.ts | 8 ++++++++ packages/angular/standalone/src/directives/toggle.ts | 8 ++++++++ 11 files changed, 88 insertions(+) diff --git a/packages/angular/standalone/src/directives/checkbox.ts b/packages/angular/standalone/src/directives/checkbox.ts index 9b20c5a8e60..31c8eef2037 100644 --- a/packages/angular/standalone/src/directives/checkbox.ts +++ b/packages/angular/standalone/src/directives/checkbox.ts @@ -29,6 +29,14 @@ const CHECKBOX_INPUTS = [ 'value', ]; +/** + * Pulling the provider into an object works + * around an ng-packagr issue that causes + * components with multiple decorators and + * a provider to be re-assigned. This re-assignment + * is not supported by Webpack and causes treeshaking + * to not work on these kinds of components. + */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => IonCheckbox), diff --git a/packages/angular/standalone/src/directives/datetime.ts b/packages/angular/standalone/src/directives/datetime.ts index 0ea911e35a7..7697dae166d 100644 --- a/packages/angular/standalone/src/directives/datetime.ts +++ b/packages/angular/standalone/src/directives/datetime.ts @@ -49,6 +49,14 @@ const DATETIME_INPUTS = [ 'yearValues', ]; +/** + * Pulling the provider into an object works + * around an ng-packagr issue that causes + * components with multiple decorators and + * a provider to be re-assigned. This re-assignment + * is not supported by Webpack and causes treeshaking + * to not work on these kinds of components. + */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => IonDatetime), diff --git a/packages/angular/standalone/src/directives/input.ts b/packages/angular/standalone/src/directives/input.ts index cb6643aad7d..49d9ccaf46d 100644 --- a/packages/angular/standalone/src/directives/input.ts +++ b/packages/angular/standalone/src/directives/input.ts @@ -60,6 +60,14 @@ const INPUT_INPUTS = [ 'value', ]; +/** + * Pulling the provider into an object works + * around an ng-packagr issue that causes + * components with multiple decorators and + * a provider to be re-assigned. This re-assignment + * is not supported by Webpack and causes treeshaking + * to not work on these kinds of components. + */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => IonInput), diff --git a/packages/angular/standalone/src/directives/radio-group.ts b/packages/angular/standalone/src/directives/radio-group.ts index a26002a191f..a6ab909b4de 100644 --- a/packages/angular/standalone/src/directives/radio-group.ts +++ b/packages/angular/standalone/src/directives/radio-group.ts @@ -18,6 +18,14 @@ import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; const RADIO_GROUP_INPUTS = ['allowEmptySelection', 'name', 'value']; +/** + * Pulling the provider into an object works + * around an ng-packagr issue that causes + * components with multiple decorators and + * a provider to be re-assigned. This re-assignment + * is not supported by Webpack and causes treeshaking + * to not work on these kinds of components. + */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => IonRadioGroup), diff --git a/packages/angular/standalone/src/directives/radio.ts b/packages/angular/standalone/src/directives/radio.ts index bfdf8720a77..c26840fe06d 100644 --- a/packages/angular/standalone/src/directives/radio.ts +++ b/packages/angular/standalone/src/directives/radio.ts @@ -18,6 +18,14 @@ import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; const RADIO_INPUTS = ['color', 'disabled', 'justify', 'labelPlacement', 'legacy', 'mode', 'name', 'value']; +/** + * Pulling the provider into an object works + * around an ng-packagr issue that causes + * components with multiple decorators and + * a provider to be re-assigned. This re-assignment + * is not supported by Webpack and causes treeshaking + * to not work on these kinds of components. + */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => IonRadio), diff --git a/packages/angular/standalone/src/directives/range.ts b/packages/angular/standalone/src/directives/range.ts index c916d29721e..c8d4b35e48c 100644 --- a/packages/angular/standalone/src/directives/range.ts +++ b/packages/angular/standalone/src/directives/range.ts @@ -42,6 +42,14 @@ const RANGE_INPUTS = [ 'value', ]; +/** + * Pulling the provider into an object works + * around an ng-packagr issue that causes + * components with multiple decorators and + * a provider to be re-assigned. This re-assignment + * is not supported by Webpack and causes treeshaking + * to not work on these kinds of components. + */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => IonRange), diff --git a/packages/angular/standalone/src/directives/searchbar.ts b/packages/angular/standalone/src/directives/searchbar.ts index 17365d1c9db..9987bd8a20a 100644 --- a/packages/angular/standalone/src/directives/searchbar.ts +++ b/packages/angular/standalone/src/directives/searchbar.ts @@ -39,6 +39,14 @@ const SEARCHBAR_INPUTS = [ 'value', ]; +/** + * Pulling the provider into an object works + * around an ng-packagr issue that causes + * components with multiple decorators and + * a provider to be re-assigned. This re-assignment + * is not supported by Webpack and causes treeshaking + * to not work on these kinds of components. + */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => IonSearchbar), diff --git a/packages/angular/standalone/src/directives/segment.ts b/packages/angular/standalone/src/directives/segment.ts index 7bdfe0e2e30..134021bcfd5 100644 --- a/packages/angular/standalone/src/directives/segment.ts +++ b/packages/angular/standalone/src/directives/segment.ts @@ -18,6 +18,14 @@ import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; const SEGMENT_INPUTS = ['color', 'disabled', 'mode', 'scrollable', 'selectOnFocus', 'swipeGesture', 'value']; +/** + * Pulling the provider into an object works + * around an ng-packagr issue that causes + * components with multiple decorators and + * a provider to be re-assigned. This re-assignment + * is not supported by Webpack and causes treeshaking + * to not work on these kinds of components. + */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => IonSegment), diff --git a/packages/angular/standalone/src/directives/select.ts b/packages/angular/standalone/src/directives/select.ts index 75915cf28b5..5866549b5b0 100644 --- a/packages/angular/standalone/src/directives/select.ts +++ b/packages/angular/standalone/src/directives/select.ts @@ -40,6 +40,14 @@ const SELECT_INPUTS = [ 'value', ]; +/** + * Pulling the provider into an object works + * around an ng-packagr issue that causes + * components with multiple decorators and + * a provider to be re-assigned. This re-assignment + * is not supported by Webpack and causes treeshaking + * to not work on these kinds of components. + */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => IonSelect), diff --git a/packages/angular/standalone/src/directives/textarea.ts b/packages/angular/standalone/src/directives/textarea.ts index f8544fbdd69..6179040cb60 100644 --- a/packages/angular/standalone/src/directives/textarea.ts +++ b/packages/angular/standalone/src/directives/textarea.ts @@ -49,6 +49,14 @@ const TEXTAREA_INPUTS = [ 'wrap', ]; +/** + * Pulling the provider into an object works + * around an ng-packagr issue that causes + * components with multiple decorators and + * a provider to be re-assigned. This re-assignment + * is not supported by Webpack and causes treeshaking + * to not work on these kinds of components. + */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => IonTextarea), diff --git a/packages/angular/standalone/src/directives/toggle.ts b/packages/angular/standalone/src/directives/toggle.ts index 9ebb874b86b..0c132587bb9 100644 --- a/packages/angular/standalone/src/directives/toggle.ts +++ b/packages/angular/standalone/src/directives/toggle.ts @@ -29,6 +29,14 @@ const TOGGLE_INPUTS = [ 'value', ]; +/** + * Pulling the provider into an object works + * around an ng-packagr issue that causes + * components with multiple decorators and + * a provider to be re-assigned. This re-assignment + * is not supported by Webpack and causes treeshaking + * to not work on these kinds of components. + */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => IonToggle), From 151d73f32e9f8f6674460a5631c09d7e219c020f Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Mon, 30 Oct 2023 16:07:16 -0400 Subject: [PATCH 6/6] add pure --- packages/angular/standalone/src/directives/checkbox.ts | 4 ++-- packages/angular/standalone/src/directives/datetime.ts | 5 +++-- packages/angular/standalone/src/directives/input.ts | 4 ++-- packages/angular/standalone/src/directives/radio-group.ts | 4 ++-- packages/angular/standalone/src/directives/radio.ts | 4 ++-- packages/angular/standalone/src/directives/range.ts | 4 ++-- packages/angular/standalone/src/directives/searchbar.ts | 4 ++-- packages/angular/standalone/src/directives/segment.ts | 4 ++-- packages/angular/standalone/src/directives/select.ts | 4 ++-- packages/angular/standalone/src/directives/textarea.ts | 4 ++-- packages/angular/standalone/src/directives/toggle.ts | 4 ++-- 11 files changed, 23 insertions(+), 22 deletions(-) diff --git a/packages/angular/standalone/src/directives/checkbox.ts b/packages/angular/standalone/src/directives/checkbox.ts index 31c8eef2037..7dad42fefc3 100644 --- a/packages/angular/standalone/src/directives/checkbox.ts +++ b/packages/angular/standalone/src/directives/checkbox.ts @@ -30,7 +30,7 @@ const CHECKBOX_INPUTS = [ ]; /** - * Pulling the provider into an object works + * Pulling the provider into an object and using PURE works * around an ng-packagr issue that causes * components with multiple decorators and * a provider to be re-assigned. This re-assignment @@ -39,7 +39,7 @@ const CHECKBOX_INPUTS = [ */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => IonCheckbox), + useExisting: /*@__PURE__*/ forwardRef(() => IonCheckbox), multi: true, }; diff --git a/packages/angular/standalone/src/directives/datetime.ts b/packages/angular/standalone/src/directives/datetime.ts index 7697dae166d..94af3a10903 100644 --- a/packages/angular/standalone/src/directives/datetime.ts +++ b/packages/angular/standalone/src/directives/datetime.ts @@ -50,16 +50,17 @@ const DATETIME_INPUTS = [ ]; /** - * Pulling the provider into an object works + * Pulling the provider into an object and using PURE works * around an ng-packagr issue that causes * components with multiple decorators and * a provider to be re-assigned. This re-assignment * is not supported by Webpack and causes treeshaking * to not work on these kinds of components. + */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => IonDatetime), + useExisting: /*@__PURE__*/ forwardRef(() => IonDatetime), multi: true, }; diff --git a/packages/angular/standalone/src/directives/input.ts b/packages/angular/standalone/src/directives/input.ts index 49d9ccaf46d..fd468746eb0 100644 --- a/packages/angular/standalone/src/directives/input.ts +++ b/packages/angular/standalone/src/directives/input.ts @@ -61,7 +61,7 @@ const INPUT_INPUTS = [ ]; /** - * Pulling the provider into an object works + * Pulling the provider into an object and using PURE works * around an ng-packagr issue that causes * components with multiple decorators and * a provider to be re-assigned. This re-assignment @@ -70,7 +70,7 @@ const INPUT_INPUTS = [ */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => IonInput), + useExisting: /*@__PURE__*/ forwardRef(() => IonInput), multi: true, }; diff --git a/packages/angular/standalone/src/directives/radio-group.ts b/packages/angular/standalone/src/directives/radio-group.ts index a6ab909b4de..ecde568d444 100644 --- a/packages/angular/standalone/src/directives/radio-group.ts +++ b/packages/angular/standalone/src/directives/radio-group.ts @@ -19,7 +19,7 @@ import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; const RADIO_GROUP_INPUTS = ['allowEmptySelection', 'name', 'value']; /** - * Pulling the provider into an object works + * Pulling the provider into an object and using PURE works * around an ng-packagr issue that causes * components with multiple decorators and * a provider to be re-assigned. This re-assignment @@ -28,7 +28,7 @@ const RADIO_GROUP_INPUTS = ['allowEmptySelection', 'name', 'value']; */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => IonRadioGroup), + useExisting: /*@__PURE__*/ forwardRef(() => IonRadioGroup), multi: true, }; diff --git a/packages/angular/standalone/src/directives/radio.ts b/packages/angular/standalone/src/directives/radio.ts index c26840fe06d..f063d22eea4 100644 --- a/packages/angular/standalone/src/directives/radio.ts +++ b/packages/angular/standalone/src/directives/radio.ts @@ -19,7 +19,7 @@ import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; const RADIO_INPUTS = ['color', 'disabled', 'justify', 'labelPlacement', 'legacy', 'mode', 'name', 'value']; /** - * Pulling the provider into an object works + * Pulling the provider into an object and using PURE works * around an ng-packagr issue that causes * components with multiple decorators and * a provider to be re-assigned. This re-assignment @@ -28,7 +28,7 @@ const RADIO_INPUTS = ['color', 'disabled', 'justify', 'labelPlacement', 'legacy' */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => IonRadio), + useExisting: /*@__PURE__*/ forwardRef(() => IonRadio), multi: true, }; diff --git a/packages/angular/standalone/src/directives/range.ts b/packages/angular/standalone/src/directives/range.ts index c8d4b35e48c..3224fa647ed 100644 --- a/packages/angular/standalone/src/directives/range.ts +++ b/packages/angular/standalone/src/directives/range.ts @@ -43,7 +43,7 @@ const RANGE_INPUTS = [ ]; /** - * Pulling the provider into an object works + * Pulling the provider into an object and using PURE works * around an ng-packagr issue that causes * components with multiple decorators and * a provider to be re-assigned. This re-assignment @@ -52,7 +52,7 @@ const RANGE_INPUTS = [ */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => IonRange), + useExisting: /*@__PURE__*/ forwardRef(() => IonRange), multi: true, }; diff --git a/packages/angular/standalone/src/directives/searchbar.ts b/packages/angular/standalone/src/directives/searchbar.ts index 9987bd8a20a..ca869982ca0 100644 --- a/packages/angular/standalone/src/directives/searchbar.ts +++ b/packages/angular/standalone/src/directives/searchbar.ts @@ -40,7 +40,7 @@ const SEARCHBAR_INPUTS = [ ]; /** - * Pulling the provider into an object works + * Pulling the provider into an object and using PURE works * around an ng-packagr issue that causes * components with multiple decorators and * a provider to be re-assigned. This re-assignment @@ -49,7 +49,7 @@ const SEARCHBAR_INPUTS = [ */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => IonSearchbar), + useExisting: /*@__PURE__*/ forwardRef(() => IonSearchbar), multi: true, }; diff --git a/packages/angular/standalone/src/directives/segment.ts b/packages/angular/standalone/src/directives/segment.ts index 134021bcfd5..cbdf5a81843 100644 --- a/packages/angular/standalone/src/directives/segment.ts +++ b/packages/angular/standalone/src/directives/segment.ts @@ -19,7 +19,7 @@ import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; const SEGMENT_INPUTS = ['color', 'disabled', 'mode', 'scrollable', 'selectOnFocus', 'swipeGesture', 'value']; /** - * Pulling the provider into an object works + * Pulling the provider into an object and using PURE works * around an ng-packagr issue that causes * components with multiple decorators and * a provider to be re-assigned. This re-assignment @@ -28,7 +28,7 @@ const SEGMENT_INPUTS = ['color', 'disabled', 'mode', 'scrollable', 'selectOnFocu */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => IonSegment), + useExisting: /*@__PURE__*/ forwardRef(() => IonSegment), multi: true, }; diff --git a/packages/angular/standalone/src/directives/select.ts b/packages/angular/standalone/src/directives/select.ts index 5866549b5b0..fa194b6ad50 100644 --- a/packages/angular/standalone/src/directives/select.ts +++ b/packages/angular/standalone/src/directives/select.ts @@ -41,7 +41,7 @@ const SELECT_INPUTS = [ ]; /** - * Pulling the provider into an object works + * Pulling the provider into an object and using PURE works * around an ng-packagr issue that causes * components with multiple decorators and * a provider to be re-assigned. This re-assignment @@ -50,7 +50,7 @@ const SELECT_INPUTS = [ */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => IonSelect), + useExisting: /*@__PURE__*/ forwardRef(() => IonSelect), multi: true, }; diff --git a/packages/angular/standalone/src/directives/textarea.ts b/packages/angular/standalone/src/directives/textarea.ts index 6179040cb60..f538bfefec2 100644 --- a/packages/angular/standalone/src/directives/textarea.ts +++ b/packages/angular/standalone/src/directives/textarea.ts @@ -50,7 +50,7 @@ const TEXTAREA_INPUTS = [ ]; /** - * Pulling the provider into an object works + * Pulling the provider into an object and using PURE works * around an ng-packagr issue that causes * components with multiple decorators and * a provider to be re-assigned. This re-assignment @@ -59,7 +59,7 @@ const TEXTAREA_INPUTS = [ */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => IonTextarea), + useExisting: /*@__PURE__*/ forwardRef(() => IonTextarea), multi: true, }; diff --git a/packages/angular/standalone/src/directives/toggle.ts b/packages/angular/standalone/src/directives/toggle.ts index 0c132587bb9..7bd3db96546 100644 --- a/packages/angular/standalone/src/directives/toggle.ts +++ b/packages/angular/standalone/src/directives/toggle.ts @@ -30,7 +30,7 @@ const TOGGLE_INPUTS = [ ]; /** - * Pulling the provider into an object works + * Pulling the provider into an object and using PURE works * around an ng-packagr issue that causes * components with multiple decorators and * a provider to be re-assigned. This re-assignment @@ -39,7 +39,7 @@ const TOGGLE_INPUTS = [ */ const accessorProvider = { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => IonToggle), + useExisting: /*@__PURE__*/ forwardRef(() => IonToggle), multi: true, };