diff --git a/packages/angular/standalone/src/directives/checkbox.ts b/packages/angular/standalone/src/directives/checkbox.ts
index 218c0483ee1..7dad42fefc3 100644
--- a/packages/angular/standalone/src/directives/checkbox.ts
+++ b/packages/angular/standalone/src/directives/checkbox.ts
@@ -7,26 +7,14 @@ import {
HostListener,
Injector,
NgZone,
+ forwardRef,
} 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';
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',
@@ -41,40 +29,42 @@ const CHECKBOX_INPUTS = [
'value',
];
+/**
+ * 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: /*@__PURE__*/ forwardRef(() => IonCheckbox),
+ multi: true,
+};
+
+@ProxyCmp({
+ defineCustomElementFn: defineCustomElement,
+ inputs: CHECKBOX_INPUTS,
+})
@Component({
selector: 'ion-checkbox',
changeDetection: ChangeDetectionStrategy.OnPush,
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 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.
- */
- proxyInputs(IonCheckbox, CHECKBOX_INPUTS);
- }
-
writeValue(value: boolean): void {
this.elementRef.nativeElement.checked = this.lastValue = value;
setIonicClasses(this.elementRef);
diff --git a/packages/angular/standalone/src/directives/datetime.ts b/packages/angular/standalone/src/directives/datetime.ts
index 4f476d7b4e2..94af3a10903 100644
--- a/packages/angular/standalone/src/directives/datetime.ts
+++ b/packages/angular/standalone/src/directives/datetime.ts
@@ -7,26 +7,14 @@ import {
HostListener,
Injector,
NgZone,
+ forwardRef,
} 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';
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',
@@ -61,43 +49,44 @@ const DATETIME_INPUTS = [
'yearValues',
];
-const DATETIME_METHODS = ['confirm', 'reset', 'cancel'];
+/**
+ * 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: /*@__PURE__*/ forwardRef(() => IonDatetime),
+ multi: true,
+};
+@ProxyCmp({
+ defineCustomElementFn: defineCustomElement,
+ inputs: DATETIME_INPUTS,
+ methods: ['confirm', 'reset', 'cancel'],
+})
@Component({
selector: 'ion-datetime',
changeDetection: ChangeDetectionStrategy.OnPush,
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 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.
- */
- proxyInputs(IonDatetime, DATETIME_INPUTS);
- proxyMethods(IonDatetime, DATETIME_METHODS);
- }
-
@HostListener('ionChange', ['$event.target'])
handleIonChange(el: HTMLIonDatetimeElement): void {
this.handleValueChange(el, el.value);
diff --git a/packages/angular/standalone/src/directives/input.ts b/packages/angular/standalone/src/directives/input.ts
index 8fb920eddbb..fd468746eb0 100644
--- a/packages/angular/standalone/src/directives/input.ts
+++ b/packages/angular/standalone/src/directives/input.ts
@@ -7,8 +7,8 @@ import {
HostListener,
Injector,
NgZone,
+ forwardRef,
} from '@angular/core';
-import type { OnInit } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ValueAccessor } from '@ionic/angular/common';
import type {
@@ -18,19 +18,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',
@@ -72,43 +60,43 @@ const INPUT_INPUTS = [
'value',
];
-const INPUT_METHODS = ['setFocus', 'getInputElement'];
+/**
+ * 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: /*@__PURE__*/ forwardRef(() => IonInput),
+ multi: true,
+};
+@ProxyCmp({
+ defineCustomElementFn: defineCustomElement,
+ inputs: INPUT_INPUTS,
+ methods: ['setFocus', 'getInputElement'],
+})
@Component({
selector: 'ion-input',
changeDetection: ChangeDetectionStrategy.OnPush,
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 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.
- */
- proxyInputs(IonInput, INPUT_INPUTS);
- proxyMethods(IonInput, INPUT_METHODS);
- }
-
@HostListener('ionInput', ['$event.target'])
handleIonInput(el: HTMLIonInputElement): void {
this.handleValueChange(el, el.value);
diff --git a/packages/angular/standalone/src/directives/radio-group.ts b/packages/angular/standalone/src/directives/radio-group.ts
index 2c6870aa16e..ecde568d444 100644
--- a/packages/angular/standalone/src/directives/radio-group.ts
+++ b/packages/angular/standalone/src/directives/radio-group.ts
@@ -7,63 +7,53 @@ import {
HostListener,
Injector,
NgZone,
+ forwardRef,
} 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';
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'];
+/**
+ * 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: /*@__PURE__*/ forwardRef(() => IonRadioGroup),
+ multi: true,
+};
+
+@ProxyCmp({
+ defineCustomElementFn: defineCustomElement,
+ inputs: RADIO_GROUP_INPUTS,
+})
@Component({
selector: 'ion-radio-group',
changeDetection: ChangeDetectionStrategy.OnPush,
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 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.
- */
- proxyInputs(IonRadioGroup, RADIO_GROUP_INPUTS);
- }
-
@HostListener('ionChange', ['$event.target'])
handleIonChange(el: HTMLIonRadioGroupElement): void {
this.handleValueChange(el, el.value);
diff --git a/packages/angular/standalone/src/directives/radio.ts b/packages/angular/standalone/src/directives/radio.ts
index d70ea8d01df..f063d22eea4 100644
--- a/packages/angular/standalone/src/directives/radio.ts
+++ b/packages/angular/standalone/src/directives/radio.ts
@@ -7,63 +7,53 @@ import {
HostListener,
Injector,
NgZone,
+ forwardRef,
} 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';
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'];
+/**
+ * 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: /*@__PURE__*/ forwardRef(() => IonRadio),
+ multi: true,
+};
+
+@ProxyCmp({
+ defineCustomElementFn: defineCustomElement,
+ inputs: RADIO_INPUTS,
+})
@Component({
selector: 'ion-radio',
changeDetection: ChangeDetectionStrategy.OnPush,
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 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.
- */
- proxyInputs(IonRadio, RADIO_INPUTS);
- }
-
@HostListener('ionSelect', ['$event.target'])
handleIonSelect(el: any): void {
/**
diff --git a/packages/angular/standalone/src/directives/range.ts b/packages/angular/standalone/src/directives/range.ts
index f77beecbe4b..3224fa647ed 100644
--- a/packages/angular/standalone/src/directives/range.ts
+++ b/packages/angular/standalone/src/directives/range.ts
@@ -7,8 +7,8 @@ import {
HostListener,
Injector,
NgZone,
+ forwardRef,
} from '@angular/core';
-import type { OnInit } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ValueAccessor } from '@ionic/angular/common';
import type {
@@ -19,19 +19,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',
@@ -54,40 +42,42 @@ const RANGE_INPUTS = [
'value',
];
+/**
+ * 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: /*@__PURE__*/ forwardRef(() => IonRange),
+ multi: true,
+};
+
+@ProxyCmp({
+ defineCustomElementFn: defineCustomElement,
+ inputs: RANGE_INPUTS,
+})
@Component({
selector: 'ion-range',
changeDetection: ChangeDetectionStrategy.OnPush,
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 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.
- */
- proxyInputs(IonRange, RANGE_INPUTS);
- }
-
@HostListener('ionChange', ['$event.target'])
handleIonChange(el: HTMLIonRangeElement): void {
this.handleValueChange(el, el.value);
diff --git a/packages/angular/standalone/src/directives/searchbar.ts b/packages/angular/standalone/src/directives/searchbar.ts
index 75f1d7da671..ca869982ca0 100644
--- a/packages/angular/standalone/src/directives/searchbar.ts
+++ b/packages/angular/standalone/src/directives/searchbar.ts
@@ -7,26 +7,14 @@ import {
HostListener,
Injector,
NgZone,
+ forwardRef,
} 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';
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',
@@ -51,43 +39,43 @@ const SEARCHBAR_INPUTS = [
'value',
];
-const SEARCHBAR_METHODS = ['setFocus', 'getInputElement'];
+/**
+ * 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: /*@__PURE__*/ forwardRef(() => IonSearchbar),
+ multi: true,
+};
+@ProxyCmp({
+ defineCustomElementFn: defineCustomElement,
+ inputs: SEARCHBAR_INPUTS,
+ methods: ['setFocus', 'getInputElement'],
+})
@Component({
selector: 'ion-searchbar',
changeDetection: ChangeDetectionStrategy.OnPush,
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 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.
- */
- proxyInputs(IonSearchbar, SEARCHBAR_INPUTS);
- proxyMethods(IonSearchbar, SEARCHBAR_METHODS);
- }
-
@HostListener('ionInput', ['$event.target'])
handleIonInput(el: HTMLIonSearchbarElement): void {
this.handleValueChange(el, el.value);
diff --git a/packages/angular/standalone/src/directives/segment.ts b/packages/angular/standalone/src/directives/segment.ts
index 5d6a16f77c0..cbdf5a81843 100644
--- a/packages/angular/standalone/src/directives/segment.ts
+++ b/packages/angular/standalone/src/directives/segment.ts
@@ -7,63 +7,53 @@ import {
HostListener,
Injector,
NgZone,
+ forwardRef,
} 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';
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'];
+/**
+ * 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: /*@__PURE__*/ forwardRef(() => IonSegment),
+ multi: true,
+};
+
+@ProxyCmp({
+ defineCustomElementFn: defineCustomElement,
+ inputs: SEGMENT_INPUTS,
+})
@Component({
selector: 'ion-segment',
changeDetection: ChangeDetectionStrategy.OnPush,
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 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.
- */
- proxyInputs(IonSegment, SEGMENT_INPUTS);
- }
-
@HostListener('ionChange', ['$event.target'])
handleIonChange(el: HTMLIonSegmentElement): void {
this.handleValueChange(el, el.value);
diff --git a/packages/angular/standalone/src/directives/select.ts b/packages/angular/standalone/src/directives/select.ts
index 0041f91d863..fa194b6ad50 100644
--- a/packages/angular/standalone/src/directives/select.ts
+++ b/packages/angular/standalone/src/directives/select.ts
@@ -7,26 +7,14 @@ import {
HostListener,
Injector,
NgZone,
+ forwardRef,
} 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';
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',
@@ -52,43 +40,43 @@ const SELECT_INPUTS = [
'value',
];
-const SELECT_METHODS = ['open'];
+/**
+ * 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: /*@__PURE__*/ forwardRef(() => IonSelect),
+ multi: true,
+};
+@ProxyCmp({
+ defineCustomElementFn: defineCustomElement,
+ inputs: SELECT_INPUTS,
+ methods: ['open'],
+})
@Component({
selector: 'ion-select',
changeDetection: ChangeDetectionStrategy.OnPush,
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 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.
- */
- proxyInputs(IonSelect, SELECT_INPUTS);
- proxyMethods(IonSelect, SELECT_METHODS);
- }
-
@HostListener('ionChange', ['$event.target'])
handleIonChange(el: HTMLIonSelectElement): void {
this.handleValueChange(el, el.value);
diff --git a/packages/angular/standalone/src/directives/textarea.ts b/packages/angular/standalone/src/directives/textarea.ts
index af5d8b49967..f538bfefec2 100644
--- a/packages/angular/standalone/src/directives/textarea.ts
+++ b/packages/angular/standalone/src/directives/textarea.ts
@@ -7,26 +7,14 @@ import {
HostListener,
Injector,
NgZone,
+ forwardRef,
} 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';
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',
@@ -61,43 +49,43 @@ const TEXTAREA_INPUTS = [
'wrap',
];
-const TEXTAREA_METHODS = ['setFocus', 'getInputElement'];
+/**
+ * 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: /*@__PURE__*/ forwardRef(() => IonTextarea),
+ multi: true,
+};
+@ProxyCmp({
+ defineCustomElementFn: defineCustomElement,
+ inputs: TEXTAREA_INPUTS,
+ methods: ['setFocus', 'getInputElement'],
+})
@Component({
selector: 'ion-textarea',
changeDetection: ChangeDetectionStrategy.OnPush,
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 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.
- */
- proxyInputs(IonTextarea, TEXTAREA_INPUTS);
- proxyMethods(IonTextarea, TEXTAREA_METHODS);
- }
-
@HostListener('ionInput', ['$event.target'])
handleIonInput(el: HTMLIonTextareaElement): void {
this.handleValueChange(el, el.value);
diff --git a/packages/angular/standalone/src/directives/toggle.ts b/packages/angular/standalone/src/directives/toggle.ts
index 1736200650f..7bd3db96546 100644
--- a/packages/angular/standalone/src/directives/toggle.ts
+++ b/packages/angular/standalone/src/directives/toggle.ts
@@ -7,26 +7,14 @@ import {
HostListener,
Injector,
NgZone,
+ forwardRef,
} 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';
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',
@@ -41,40 +29,42 @@ const TOGGLE_INPUTS = [
'value',
];
+/**
+ * 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: /*@__PURE__*/ forwardRef(() => IonToggle),
+ multi: true,
+};
+
+@ProxyCmp({
+ defineCustomElementFn: defineCustomElement,
+ inputs: TOGGLE_INPUTS,
+})
@Component({
selector: 'ion-toggle',
changeDetection: ChangeDetectionStrategy.OnPush,
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 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.
- */
- proxyInputs(IonToggle, TOGGLE_INPUTS);
- }
-
writeValue(value: boolean): void {
this.elementRef.nativeElement.checked = this.lastValue = value;
setIonicClasses(this.elementRef);
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..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
@@ -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,10 +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', () => {
@@ -150,10 +113,6 @@ describe('Value Accessors', () => {
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 +130,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 +145,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/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/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
-
+