fix(angular): null values are not converted to falsy value (#26341)

BREAKING CHANGE:

Datetime:

Passing the empty string to the `value` property will now error as it is not a valid ISO-8601 value.

Angular:

`null` values on form components will no longer be converted to the empty string (`''`) or `false`. This impacts `ion-checkbox`, `ion-datetime`, `ion-input`, `ion-radio`, `ion-radio-group`, ion-range`, `ion-searchbar`, `ion-segment`, `ion-select`, `ion-textarea`, and `ion-toggle`.
This commit is contained in:
Liam DeBeasi
2022-11-23 13:03:13 -05:00
committed by GitHub
parent 1e855e7699
commit ce2e37b1a1
6 changed files with 21 additions and 16 deletions

View File

@ -35,6 +35,7 @@ This is a comprehensive list of the breaking changes introduced in the major ver
- [Types](#version-7x-types) - [Types](#version-7x-types)
- [Overlay Attribute Interfaces](#version-7x-overlay-attribute-interfaces) - [Overlay Attribute Interfaces](#version-7x-overlay-attribute-interfaces)
- [JavaScript Frameworks](#version-7x-javascript-frameworks) - [JavaScript Frameworks](#version-7x-javascript-frameworks)
- [Angular](#version-7x-angular)
- [React](#version-7x-react) - [React](#version-7x-react)
- [Vue](#version-7x-vue) - [Vue](#version-7x-vue)
- [Utilities](#version-7x-utilities) - [Utilities](#version-7x-utilities)
@ -101,6 +102,8 @@ This section details the desktop browser, JavaScript framework, and mobile platf
- Datetime no longer incorrectly reports the time zone when `value` is updated. Datetime does not manage time zones, so any time zone information provided is ignored. - Datetime no longer incorrectly reports the time zone when `value` is updated. Datetime does not manage time zones, so any time zone information provided is ignored.
- Passing the empty string to the `value` property will now error as it is not a valid ISO-8601 value.
<h4 id="version-7x-input">Input</h4> <h4 id="version-7x-input">Input</h4>
- `ionChange` is no longer emitted when the `value` of `ion-input` is modified externally. `ionChange` is only emitted from user committed changes, such as typing in the input and the input losing focus or from clicking the clear action within the input. - `ionChange` is no longer emitted when the `value` of `ion-input` is modified externally. `ionChange` is only emitted from user committed changes, such as typing in the input and the input losing focus or from clicking the clear action within the input.
@ -223,6 +226,10 @@ Any references to the virtual scroll types from `@ionic/core` have been removed.
<h2 id="version-7x-javascript-frameworks">JavaScript Frameworks</h2> <h2 id="version-7x-javascript-frameworks">JavaScript Frameworks</h2>
<h4 id="version-7x-angular">Angular</h4>
- `null` values on form components will no longer be converted to the empty string (`''`) or `false`. This impacts `ion-checkbox`, `ion-datetime`, `ion-input`, `ion-radio`, `ion-radio-group`, ion-range`, `ion-searchbar`, `ion-segment`, `ion-select`, `ion-textarea`, and `ion-toggle`.
<h4 id="version-7x-react">React</h4> <h4 id="version-7x-react">React</h4>
`@ionic/react` and `@ionic/react-router` no longer ship a CommonJS entry point. Instead, only an ES Module entry point is provided for improved compatibility with Vite. `@ionic/react` and `@ionic/react-router` no longer ship a CommonJS entry point. Instead, only an ES Module entry point is provided for improved compatibility with Vite.

View File

@ -19,7 +19,7 @@ export class BooleanValueAccessorDirective extends ValueAccessor {
} }
writeValue(value: any): void { writeValue(value: any): void {
this.el.nativeElement.checked = this.lastValue = value == null ? false : value; this.el.nativeElement.checked = this.lastValue = value;
setIonicClasses(this.el); setIonicClasses(this.el);
} }

View File

@ -18,14 +18,7 @@ export class ValueAccessor implements ControlValueAccessor, AfterViewInit, OnDes
constructor(protected injector: Injector, protected el: ElementRef) {} constructor(protected injector: Injector, protected el: ElementRef) {}
writeValue(value: any): void { writeValue(value: any): void {
/** this.el.nativeElement.value = this.lastValue = value;
* TODO FW-2646
* Change `value == null ? '' : value;`
* to `value`. This was a fix for IE9, but IE9
* is no longer supported; however, this change
* is potentially a breaking change
*/
this.el.nativeElement.value = this.lastValue = value == null ? '' : value;
setIonicClasses(this.el); setIonicClasses(this.el);
} }

View File

@ -16,9 +16,15 @@ describe('Inputs', () => {
cy.get('ion-checkbox').should('have.prop', 'checked').and('equal', false); cy.get('ion-checkbox').should('have.prop', 'checked').and('equal', false);
cy.get('ion-toggle').should('have.prop', 'checked').and('equal', false); cy.get('ion-toggle').should('have.prop', 'checked').and('equal', false);
cy.get('ion-input').should('have.prop', 'value').and('equal', ''); /**
cy.get('ion-datetime').should('have.prop', 'value').and('equal', ''); * The `value` property gets set to undefined
cy.get('ion-select').should('have.prop', 'value').and('equal', ''); * for these components, so we need to check
* not.have.prop which will check that the
* value property is undefined.
*/
cy.get('ion-input').should('not.have.prop', 'value');
cy.get('ion-datetime').should('not.have.prop', 'value');
cy.get('ion-select').should('not.have.prop', 'value');
}); });
it('should get some value', () => { it('should get some value', () => {

View File

@ -160,8 +160,7 @@ export class DatetimeButton implements ComponentInterface {
* to keep checking if the datetime value is `string` or `string[]`. * to keep checking if the datetime value is `string` or `string[]`.
*/ */
private getParsedDateValues = (value?: string[] | string | null): string[] => { private getParsedDateValues = (value?: string[] | string | null): string[] => {
// TODO FW-2646 Remove value === '' if (value === undefined || value === null) {
if (value === '' || value === undefined || value === null) {
return []; return [];
} }

View File

@ -1171,7 +1171,7 @@ export class Datetime implements ComponentInterface {
} }
private processValue = (value?: string | string[] | null) => { private processValue = (value?: string | string[] | null) => {
const hasValue = value !== '' && value !== null && value !== undefined; const hasValue = value !== null && value !== undefined;
const valueToProcess = hasValue ? parseDate(value) : this.defaultParts; const valueToProcess = hasValue ? parseDate(value) : this.defaultParts;
const { minParts, maxParts } = this; const { minParts, maxParts } = this;
@ -1283,7 +1283,7 @@ export class Datetime implements ComponentInterface {
}; };
private hasValue = () => { private hasValue = () => {
return this.value != null && this.value !== ''; return this.value != null;
}; };
private nextMonth = () => { private nextMonth = () => {