-
Notifications
You must be signed in to change notification settings - Fork 13.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(angular): standalone form controls can participate in forms (#28125
) Issue number: N/A --------- <!-- Please do not submit updates to dependencies unless it fixes an issue. --> <!-- Please try to limit your pull request to one type (bugfix, feature, etc). Submit multiple pull requests if needed. --> ## What is the current behavior? <!-- Please describe the current behavior that you are modifying. --> Ionic standalone form controls cannot participate in Angular forms. ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> - Ionic form controls can participate in Angular forms by importing the standalone component - Applies to: `ion-input`, `ion-textarea`, `ion-searchbar`, `ion-toggle`, `ion-checkbox`, `ion-segment`, `ion-radio`, `ion-radio-group`, `ion-datetime` and `ion-range`. - Refactors `ValueAccessor` from `@ionic/angular` to `@ionic/angular/common` - Refactors `raf` utility from `@ionic/angular` to `@ionic/angular/common` ## Does this introduce a breaking change? - [ ] Yes - [x] No <!-- If this introduces a breaking change, please describe the impact and migration path for existing applications below. --> ## Other information <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> ---------
- Loading branch information
1 parent
dad7e66
commit 28f2ec9
Showing
47 changed files
with
1,626 additions
and
902 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
packages/angular/common/src/directives/control-value-accessors/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './value-accessor'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 1 addition & 2 deletions
3
packages/angular/src/directives/control-value-accessors/numeric-value-accessor.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 1 addition & 2 deletions
3
packages/angular/src/directives/control-value-accessors/select-value-accessor.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 1 addition & 2 deletions
3
packages/angular/src/directives/control-value-accessors/text-value-accessor.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import { | ||
ChangeDetectionStrategy, | ||
ChangeDetectorRef, | ||
Component, | ||
ElementRef, | ||
EventEmitter, | ||
HostListener, | ||
Injector, | ||
NgZone, | ||
} 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'; | ||
|
||
import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; | ||
|
||
const CHECKBOX_INPUTS = [ | ||
'checked', | ||
'color', | ||
'disabled', | ||
'indeterminate', | ||
'justify', | ||
'labelPlacement', | ||
'legacy', | ||
'mode', | ||
'name', | ||
'value', | ||
]; | ||
|
||
@ProxyCmp({ | ||
defineCustomElementFn: defineCustomElement, | ||
inputs: CHECKBOX_INPUTS, | ||
}) | ||
@Component({ | ||
selector: 'ion-checkbox', | ||
changeDetection: ChangeDetectionStrategy.OnPush, | ||
template: '<ng-content></ng-content>', | ||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property | ||
inputs: CHECKBOX_INPUTS, | ||
providers: [ | ||
{ | ||
provide: NG_VALUE_ACCESSOR, | ||
useExisting: IonCheckbox, | ||
multi: true, | ||
}, | ||
], | ||
standalone: true, | ||
}) | ||
export class IonCheckbox extends ValueAccessor { | ||
protected el: HTMLElement; | ||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { | ||
super(injector, r); | ||
c.detach(); | ||
this.el = r.nativeElement; | ||
proxyOutputs(this, this.el, ['ionChange', 'ionFocus', 'ionBlur']); | ||
} | ||
|
||
writeValue(value: boolean): void { | ||
this.elementRef.nativeElement.checked = this.lastValue = value; | ||
setIonicClasses(this.elementRef); | ||
} | ||
|
||
@HostListener('ionChange', ['$event.target']) | ||
handleIonChange(el: HTMLIonCheckboxElement | HTMLIonToggleElement): void { | ||
this.handleValueChange(el, el.checked); | ||
} | ||
} | ||
|
||
export declare interface IonCheckbox extends Components.IonCheckbox { | ||
/** | ||
* Emitted when the checked property has changed | ||
as a result of a user action such as a click. | ||
This event will not emit when programmatically | ||
setting the checked property. | ||
*/ | ||
ionChange: EventEmitter<CustomEvent<CheckboxChangeEventDetail>>; | ||
/** | ||
* Emitted when the checkbox has focus. | ||
*/ | ||
ionFocus: EventEmitter<CustomEvent<void>>; | ||
/** | ||
* Emitted when the checkbox loses focus. | ||
*/ | ||
ionBlur: EventEmitter<CustomEvent<void>>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import { | ||
ChangeDetectionStrategy, | ||
ChangeDetectorRef, | ||
Component, | ||
ElementRef, | ||
EventEmitter, | ||
HostListener, | ||
Injector, | ||
NgZone, | ||
} 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'; | ||
|
||
import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; | ||
|
||
const DATETIME_INPUTS = [ | ||
'cancelText', | ||
'clearText', | ||
'color', | ||
'dayValues', | ||
'disabled', | ||
'doneText', | ||
'firstDayOfWeek', | ||
'highlightedDates', | ||
'hourCycle', | ||
'hourValues', | ||
'isDateEnabled', | ||
'locale', | ||
'max', | ||
'min', | ||
'minuteValues', | ||
'mode', | ||
'monthValues', | ||
'multiple', | ||
'name', | ||
'preferWheel', | ||
'presentation', | ||
'readonly', | ||
'showClearButton', | ||
'showDefaultButtons', | ||
'showDefaultTimeLabel', | ||
'showDefaultTitle', | ||
'size', | ||
'titleSelectedDatesFormatter', | ||
'value', | ||
'yearValues', | ||
]; | ||
|
||
@ProxyCmp({ | ||
defineCustomElementFn: defineCustomElement, | ||
inputs: DATETIME_INPUTS, | ||
methods: ['confirm', 'reset', 'cancel'], | ||
}) | ||
@Component({ | ||
selector: 'ion-datetime', | ||
changeDetection: ChangeDetectionStrategy.OnPush, | ||
template: '<ng-content></ng-content>', | ||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property | ||
inputs: DATETIME_INPUTS, | ||
providers: [ | ||
{ | ||
provide: NG_VALUE_ACCESSOR, | ||
useExisting: IonDatetime, | ||
multi: true, | ||
}, | ||
], | ||
standalone: true, | ||
}) | ||
export class IonDatetime extends ValueAccessor { | ||
protected el: HTMLElement; | ||
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone, injector: Injector) { | ||
super(injector, r); | ||
c.detach(); | ||
this.el = r.nativeElement; | ||
proxyOutputs(this, this.el, ['ionCancel', 'ionChange', 'ionFocus', 'ionBlur']); | ||
} | ||
|
||
@HostListener('ionChange', ['$event.target']) | ||
handleIonChange(el: HTMLIonDatetimeElement): void { | ||
this.handleValueChange(el, el.value); | ||
} | ||
} | ||
|
||
export declare interface IonDatetime extends Components.IonDatetime { | ||
/** | ||
* Emitted when the datetime selection was cancelled. | ||
*/ | ||
ionCancel: EventEmitter<CustomEvent<void>>; | ||
/** | ||
* Emitted when the value (selected date) has changed. | ||
*/ | ||
ionChange: EventEmitter<CustomEvent<DatetimeChangeEventDetail>>; | ||
/** | ||
* Emitted when the datetime has focus. | ||
*/ | ||
ionFocus: EventEmitter<CustomEvent<void>>; | ||
/** | ||
* Emitted when the datetime loses focus. | ||
*/ | ||
ionBlur: EventEmitter<CustomEvent<void>>; | ||
} |
Oops, something went wrong.