From e6122b86eae5608c09b1082d75f21752f90e12d4 Mon Sep 17 00:00:00 2001 From: rudrakshagarwal4200-ai Date: Sat, 17 Oct 2026 03:43:53 +0530 Subject: [PATCH 1/3] Improve compareWith utility for better null handling Enhance comparison logic to handle undefined and null values. --- core/src/utils/forms/compare-with-utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/utils/forms/compare-with-utils.ts b/core/src/utils/forms/compare-with-utils.ts index 2ab1fd0237b..b342132920a 100644 --- a/core/src/utils/forms/compare-with-utils.ts +++ b/core/src/utils/forms/compare-with-utils.ts @@ -15,7 +15,7 @@ export const compareOptions = ( if (typeof compareWith === 'function') { return compareWith(currentValue, compareValue); } else if (typeof compareWith === 'string') { - return currentValue[compareWith] === compareValue[compareWith]; + return currentValue?.[compareWith] !== undefined && currentValue?.[compareWith] === compareValue?.[compareWith]; } else { return Array.isArray(compareValue) ? compareValue.includes(currentValue) : currentValue === compareValue; } @@ -33,7 +33,7 @@ export const isOptionSelected = ( compareValue: any, compareWith?: string | CompareFn | null ) => { - if (currentValue === undefined) { + if (currentValue === undefined || currentValue === null) { return false; } if (Array.isArray(currentValue)) { From b519c62b413df414e28d43722df39a806a2f6339 Mon Sep 17 00:00:00 2001 From: rudrakshagarwal4200-ai Date: Sat, 17 Oct 2026 03:44:43 +0530 Subject: [PATCH 2/3] Update radio group selection logic Refactor radio selection logic to use isOptionSelected for better comparison. --- core/src/components/radio-group/radio-group.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/src/components/radio-group/radio-group.tsx b/core/src/components/radio-group/radio-group.tsx index 37e0f0da0c9..4659d4e1d7e 100644 --- a/core/src/components/radio-group/radio-group.tsx +++ b/core/src/components/radio-group/radio-group.tsx @@ -1,6 +1,6 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core'; import { Build, Component, Element, Event, Host, Listen, Method, Prop, State, Watch, h } from '@stencil/core'; -import { checkInvalidState } from '@utils/forms'; +import { checkInvalidState, isOptionSelected } from '@utils/forms'; import { renderHiddenInput } from '@utils/helpers'; import { getIonMode } from '../../global/ionic-global'; @@ -104,7 +104,7 @@ export class RadioGroup implements ComponentInterface { // Get the first radio that is not disabled and the checked one const first = radios.find((radio) => !radio.disabled); - const checked = radios.find((radio) => radio.value === value && !radio.disabled); + const checked = radios.find((radio) => isOptionSelected(value, radio.value, this.compareWith) && !radio.disabled); if (!first && !checked) { return; @@ -219,7 +219,8 @@ export class RadioGroup implements ComponentInterface { if (selectedRadio && !selectedRadio.disabled) { const currentValue = this.value; const newValue = selectedRadio.value; - if (newValue !== currentValue) { + const isSelected = isOptionSelected(currentValue, newValue, this.compareWith); + if (!isSelected) { this.value = newValue; this.emitValueChange(ev); } else if (this.allowEmptySelection) { @@ -275,7 +276,8 @@ export class RadioGroup implements ComponentInterface { // space bar on top of a selected radio if ([' '].includes(ev.key)) { const previousValue = this.value; - this.value = this.allowEmptySelection && this.value !== undefined ? undefined : current.value; + const isSelected = isOptionSelected(this.value, current.value, this.compareWith); + this.value = this.allowEmptySelection && isSelected ? undefined : current.value; if (previousValue !== this.value || this.allowEmptySelection) { /** * Value change should only be emitted if the value is different, From 8e350ef41b685ba0e4876a6c7851dc09fcc3058f Mon Sep 17 00:00:00 2001 From: rudrakshagarwal4200-ai Date: Sat, 17 Oct 2026 03:45:41 +0530 Subject: [PATCH 3/3] Enhance radio-group tests for deselection and null values Added tests for radio group deselection and null handling. --- .../radio-group/test/radio-group.spec.tsx | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/core/src/components/radio-group/test/radio-group.spec.tsx b/core/src/components/radio-group/test/radio-group.spec.tsx index fdd6c644267..cd13bd2acb3 100644 --- a/core/src/components/radio-group/test/radio-group.spec.tsx +++ b/core/src/components/radio-group/test/radio-group.spec.tsx @@ -108,4 +108,43 @@ describe('ion-radio-group', () => { expect(radios[2].getAttribute('aria-checked')).toBe('true'); expect(radioGroup.value).toEqual(3); }); + + it('should allow deselection with compareWith when allowEmptySelection is true', async () => { + const page = await newSpecPage({ + components: [Radio, RadioGroup], + template: () => ( + + Option #1 + Option #2 + + ), + }); + + const radioGroup = page.body.querySelector('ion-radio-group')!; + const radios = document.querySelectorAll('ion-radio')!; + + expect(radios[0].getAttribute('aria-checked')).toBe('true'); + + await radios[0].click(); + await page.waitForChanges(); + + expect(radioGroup.value).toBeUndefined(); + expect(radios[0].getAttribute('aria-checked')).toBe('false'); + }); + + it('should handle null values safely when compareWith is a property name', async () => { + const page = await newSpecPage({ + components: [Radio, RadioGroup], + template: () => ( + + Option #1 + Option #2 + + ), + }); + + const radios = document.querySelectorAll('ion-radio')!; + expect(radios[0].getAttribute('aria-checked')).toBe('false'); + expect(radios[1].getAttribute('aria-checked')).toBe('false'); + }); });