diff --git a/CHANGELOG.md b/CHANGELOG.md
index 05a3c13bb20..bf83fc33a69 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -68,6 +68,11 @@ All notable changes for each version of this project will be documented in this
### Bug Fixes
+- **Forms**
+ - `IgxSnackbarComponent` - The default action button now renders with `type="button"`. Previously, when the snackbar was inside a `form` (for example as part of a grid), it became the default button of the form, so pressing Enter in any input of the form clicked it, which triggered the snackbar action and submitted the form.
+ - `IgxQueryBuilderComponent` - The add expression and the group (AND/OR) buttons now render with `type="button"`. Previously, clicking them inside a `form` submitted it. Pressing Enter in the query builder inputs also no longer submits a surrounding `form`.
+ - `IgxGridComponent`, `IgxTreeGridComponent`, `IgxHierarchicalGridComponent`, `IgxPivotGridComponent` - Pressing Enter in the grid UI, such as the filtering row, cell and row editors, the toolbar column hiding and pinning, Excel-style filtering and advanced filtering, as well as selecting a date in their date pickers with Enter, no longer submits a surrounding `form`.
+ - `IgxAdvancedFilteringDialogComponent`, `IgxColumnActionsComponent`, `IgxPivotDataSelectorComponent` - Pressing Enter in their inputs no longer submits a surrounding `form` when they are rendered outside of the grid, e.g. used standalone, or the advanced filtering dialog opened with custom overlay settings.
- `IgxAccordionComponent`
- When `singleBranchExpand` is set initially and the panels are rendered with `@for`, the panels collapsed on init no longer keep `aria-expanded="true"` and no `ExpressionChangedAfterItHasBeenCheckedError` is thrown in development mode.
- `IgxCarouselComponent`
diff --git a/projects/igniteui-angular/core/src/core/utils.spec.ts b/projects/igniteui-angular/core/src/core/utils.spec.ts
index 131b514e7cc..b8214ba2ad0 100644
--- a/projects/igniteui-angular/core/src/core/utils.spec.ts
+++ b/projects/igniteui-angular/core/src/core/utils.spec.ts
@@ -1,7 +1,7 @@
import { SampleTestData } from 'igniteui-angular/test-utils/sample-test-data.spec';
import { cloneValue, cloneValueCached, cloneHierarchicalArray, compareMaps, getComponentCssSizeVar,
- intoChunks, isDate, isLeftToRight, isObject, showMessage, uniqueDates } from './utils';
-import { describe, it, expect } from 'vitest';
+ intoChunks, isDate, isLeftToRight, isObject, preventImplicitSubmission, showMessage, uniqueDates } from './utils';
+import { describe, it, expect, beforeEach, afterEach } from 'vitest';
describe('Utils', () => {
const complexObject = {
@@ -430,4 +430,58 @@ describe('Utils', () => {
expect(isDate(variable)).toBeFalsy();
});
});
+
+ describe('Utils - preventImplicitSubmission() unit tests', () => {
+ let host: HTMLDivElement;
+
+ const dispatchKeydown = (target: Element, init: KeyboardEventInit = {}): boolean => {
+ const event = new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, cancelable: true, composed: true, ...init });
+ target.dispatchEvent(event);
+ return event.defaultPrevented;
+ };
+
+ beforeEach(() => {
+ host = document.createElement('div');
+ host.addEventListener('keydown', preventImplicitSubmission);
+ document.body.appendChild(host);
+ });
+
+ afterEach(() => {
+ host.remove();
+ });
+
+ it('should prevent Enter only on a form-owned input which would submit the form', () => {
+ host.innerHTML = '
';
+ const [textInput, fileInput] = Array.from(host.querySelectorAll('form input'));
+
+ expect(dispatchKeydown(textInput)).toBe(true);
+ expect(dispatchKeydown(fileInput)).toBe(false);
+ expect(dispatchKeydown(host.querySelector('#noForm')!)).toBe(false);
+ });
+
+ it('should not prevent other keys than Enter', () => {
+ host.innerHTML = '';
+ const input = host.querySelector('input')!;
+
+ expect(dispatchKeydown(input, { key: 'a' })).toBe(false);
+ expect(dispatchKeydown(input, { key: ' ' })).toBe(false);
+ });
+
+ it('should not prevent Enter while an IME composition is in progress', () => {
+ host.innerHTML = '';
+
+ expect(dispatchKeydown(host.querySelector('input')!, { isComposing: true })).toBe(false);
+ });
+
+ it('should resolve the target of the event through its composed path', () => {
+ const shadowHost = document.createElement('div');
+ host.appendChild(shadowHost);
+ const shadowRoot = shadowHost.attachShadow({ mode: 'open' });
+ shadowRoot.innerHTML = '';
+ const input = shadowRoot.querySelector('input')!;
+
+ expect(input.form).toBe(shadowRoot.querySelector('form'));
+ expect(dispatchKeydown(input)).toBe(true);
+ });
+ });
});
diff --git a/projects/igniteui-angular/core/src/core/utils.ts b/projects/igniteui-angular/core/src/core/utils.ts
index f7f4a9e4185..cc494fb9532 100644
--- a/projects/igniteui-angular/core/src/core/utils.ts
+++ b/projects/igniteui-angular/core/src/core/utils.ts
@@ -481,6 +481,25 @@ export const NAVIGATION_KEYS = new Set([
' '
]);
+/** Input types on which Enter has its own activation behavior instead of submitting the form. */
+const ACTIVATABLE_INPUT_TYPES = new Set(['button', 'submit', 'reset', 'image', 'file', 'color']);
+
+/**
+ * @hidden
+ * @internal
+ *
+ * Cancels the implicit submission of the surrounding form, which the browser performs as the default action
+ * of an Enter keydown in an ``.
+ * Only inputs which have a form owner and no activation behavior of their own are affected.
+ */
+export function preventImplicitSubmission(event: KeyboardEvent): void {
+ const target = event.composedPath()[0];
+ if (event.key === 'Enter' && !event.isComposing && target instanceof HTMLInputElement &&
+ target.form && !ACTIVATABLE_INPUT_TYPES.has(target.type)) {
+ event.preventDefault();
+ }
+}
+
/**
* @hidden
* @internal
diff --git a/projects/igniteui-angular/grids/core/src/column-actions/column-actions.component.html b/projects/igniteui-angular/grids/core/src/column-actions/column-actions.component.html
index f111f4e0953..04c697d9d45 100644
--- a/projects/igniteui-angular/grids/core/src/column-actions/column-actions.component.html
+++ b/projects/igniteui-angular/grids/core/src/column-actions/column-actions.component.html
@@ -14,6 +14,7 @@
}
diff --git a/projects/igniteui-angular/grids/core/src/column-actions/column-actions.component.ts b/projects/igniteui-angular/grids/core/src/column-actions/column-actions.component.ts
index 61de8da3ee9..510a1d059c8 100644
--- a/projects/igniteui-angular/grids/core/src/column-actions/column-actions.component.ts
+++ b/projects/igniteui-angular/grids/core/src/column-actions/column-actions.component.ts
@@ -25,7 +25,7 @@ import { FormsModule } from '@angular/forms';
import { IgxInputDirective, IgxInputGroupComponent } from 'igniteui-angular/input-group';
import { IgxCheckboxComponent } from 'igniteui-angular/checkbox';
import { IgxButtonDirective, IgxRippleDirective } from 'igniteui-angular/directives';
-import { ColumnType } from 'igniteui-angular/core';
+import { ColumnType, preventImplicitSubmission } from 'igniteui-angular/core';
let NEXT_ID = 0;
/**
@@ -45,6 +45,8 @@ let NEXT_ID = 0;
export class IgxColumnActionsComponent implements DoCheck {
private differs = inject(IterableDiffers);
+ protected readonly preventImplicitSubmission = preventImplicitSubmission;
+
/**
* Gets/Sets the grid to provide column actions for.
diff --git a/projects/igniteui-angular/grids/grid/src/grid-base.directive.ts b/projects/igniteui-angular/grids/grid/src/grid-base.directive.ts
index 18098e8e9c9..40c06f19ee8 100644
--- a/projects/igniteui-angular/grids/grid/src/grid-base.directive.ts
+++ b/projects/igniteui-angular/grids/grid/src/grid-base.directive.ts
@@ -103,7 +103,8 @@ import {
runAfterRenderOnce,
GridStyleCSSProperty,
I18N_FORMATTER,
- IgxStylesRegistrar
+ IgxStylesRegistrar,
+ preventImplicitSubmission
} from 'igniteui-angular/core';
import { IgcTrialWatermark } from 'igniteui-trial-watermark';
import {
@@ -3827,6 +3828,12 @@ export abstract class IgxGridBaseDirective implements GridType,
*/
public _setupListeners() {
const destructor = takeUntil(this.destroy$);
+ // Capture phase, since internal handlers (filtering row, editors, dialogs) stop the propagation of key events.
+ // The keypress is also handled, as a picker selecting on Enter may move the focus to its input before it.
+ merge(
+ fromEvent(this.nativeElement, 'keydown', { capture: true }),
+ fromEvent(this.nativeElement, 'keypress', { capture: true })
+ ).pipe(destructor).subscribe(preventImplicitSubmission);
fromEvent(this.nativeElement, 'focusout').pipe(filter(() => !!this.navigation.activeNode), destructor).subscribe((event) => {
const activeNode = this.navigation.activeNode;
if (!this.crudService.cell && !!activeNode &&
diff --git a/projects/igniteui-angular/grids/grid/src/grid-form-submission.spec.ts b/projects/igniteui-angular/grids/grid/src/grid-form-submission.spec.ts
new file mode 100644
index 00000000000..36de95a2b50
--- /dev/null
+++ b/projects/igniteui-angular/grids/grid/src/grid-form-submission.spec.ts
@@ -0,0 +1,283 @@
+import { ChangeDetectionStrategy, Component, ViewChild } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { IgxGridComponent } from './grid.component';
+import { FilterMode, IgxCellTemplateDirective, IgxColumnActionsComponent, IgxColumnComponent, IgxColumnHidingDirective, IgxGridToolbarActionsComponent, IgxGridToolbarComponent, IgxGridToolbarHidingComponent } from 'igniteui-angular/grids/core';
+import { AbsoluteScrollStrategy, GlobalPositionStrategy } from 'igniteui-angular/core';
+import { IgxInputDirective } from 'igniteui-angular/input-group';
+import { IgxDatePickerComponent } from 'igniteui-angular/date-picker';
+import { GridFunctions } from '../../../test-utils/grid-functions.spec';
+import { QueryBuilderFunctions } from '../../../query-builder/src/query-builder/query-builder-functions.spec';
+import { firstValueFrom } from 'rxjs';
+import { userEvent } from 'vitest/browser';
+import { describe, it, expect, beforeEach } from 'vitest';
+
+const FILTER_UI_ROW = 'igx-grid-filtering-row';
+const UNTYPED_BUTTONS = 'button:not([type]), button[type=submit]';
+
+const DATA = [
+ { ProductID: 1, ProductName: 'Chai', InStock: true, Released: new Date(2024, 0, 10) },
+ { ProductID: 2, ProductName: 'Aniseed Syrup', InStock: false, Released: new Date(2024, 1, 11) },
+ { ProductID: 3, ProductName: 'Chef Antons Cajun Seasoning', InStock: true, Released: new Date(2024, 2, 12) }
+];
+
+const pressEnter = (target: Element): KeyboardEvent => {
+ const event = new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, cancelable: true, composed: true });
+ target.dispatchEvent(event);
+ return event;
+};
+
+const addAdvancedFilteringCondition = async (fixture: ComponentFixture): Promise => {
+ QueryBuilderFunctions.clickQueryBuilderInitialAddConditionBtn(fixture, 0);
+ await fixture.whenStable();
+ fixture.detectChanges();
+ await QueryBuilderFunctions.selectColumnInEditModeExpression(fixture, 1); // 'ProductName'
+ await QueryBuilderFunctions.selectOperatorInEditModeExpression(fixture, 2); // 'Starts With'
+ return QueryBuilderFunctions.getQueryBuilderValueInput(fixture)!.querySelector('input')!;
+};
+
+describe('IgxGrid - implicit form submission #grid', () => {
+ let fixture: ComponentFixture;
+ let grid: IgxGridComponent;
+ let form: HTMLFormElement;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [NoopAnimationsModule, GridInFormComponent]
+ }).compileComponents();
+ });
+
+ beforeEach(async () => {
+ fixture = TestBed.createComponent(GridInFormComponent);
+ fixture.detectChanges();
+ await fixture.whenStable();
+ fixture.detectChanges();
+ grid = fixture.componentInstance.grid;
+ form = fixture.nativeElement.querySelector('form');
+ });
+
+ it('should not render buttons which can become the default button of the form', () => {
+ // The add row snackbar is always rendered and was the default button of the form before the fix.
+ expect(grid.nativeElement.querySelector('igx-snackbar button')!.getAttribute('type')).toBe('button');
+ expect(grid.nativeElement.querySelectorAll(UNTYPED_BUTTONS).length).toBe(0);
+ const defaultButton = form.querySelector('button:not([type]), button[type=submit], input[type=submit]');
+ expect(defaultButton!.id).toBe('submit');
+ });
+
+ it('should prevent implicit submission on Enter in the filtering row input', async () => {
+ GridFunctions.clickFilterCellChipUI(fixture, 'ProductName');
+ await fixture.whenStable();
+ fixture.detectChanges();
+
+ const input: HTMLInputElement = fixture.debugElement.query(By.css(FILTER_UI_ROW)).query(By.directive(IgxInputDirective)).nativeElement;
+ expect(input.form).toBe(form);
+ expect(pressEnter(input).defaultPrevented).toBe(true);
+
+ await userEvent.click(input);
+ for (const key of 'Chai') {
+ await userEvent.keyboard(key);
+ await fixture.whenStable();
+ await new Promise(resolve => requestAnimationFrame(resolve));
+ fixture.detectChanges();
+ }
+ expect(input.value).toBe('Chai');
+
+ await userEvent.keyboard('{Enter}');
+ await fixture.whenStable();
+ await new Promise(resolve => requestAnimationFrame(resolve));
+ fixture.detectChanges();
+
+ expect(grid.filteredData?.map(r => r.ProductName)).toEqual(['Chai']);
+ expect(fixture.componentInstance.submits).toBe(0);
+ });
+
+ it('should prevent implicit submission on Enter in a cell editor', () => {
+ const cell = grid.getCellByColumn(0, 'ProductName');
+ cell.editMode = true;
+ fixture.detectChanges();
+
+ const input: HTMLInputElement = grid.nativeElement.querySelector('.igx-grid__td--editing input')!;
+ expect(input.form).toBe(form);
+ expect(pressEnter(input).defaultPrevented).toBe(true);
+ });
+
+ it('should prevent implicit submission on Enter in the toolbar column hiding search input', async () => {
+ const hidingButton: HTMLButtonElement = fixture.nativeElement.querySelector('igx-grid-toolbar-hiding button');
+ hidingButton.click();
+ await fixture.whenStable();
+ fixture.detectChanges();
+
+ const input: HTMLInputElement = grid.nativeElement.querySelector('igx-column-actions input')!;
+ expect(input.form).toBe(form);
+ expect(pressEnter(input).defaultPrevented).toBe(true);
+ });
+
+ it('should prevent implicit submission on Enter in the excel style filtering custom dialog input', async () => {
+ grid.filterMode = FilterMode.excelStyleFilter;
+ fixture.detectChanges();
+
+ await GridFunctions.clickExcelFilterIconFromCode(fixture, grid, 'ProductName');
+ GridFunctions.clickExcelFilterCascadeButton(fixture);
+ await fixture.whenStable();
+ fixture.detectChanges();
+ GridFunctions.clickOperatorFromCascadeMenu(fixture, 0);
+ await fixture.whenStable();
+ fixture.detectChanges();
+
+ const input = GridFunctions.getExcelFilteringInput(fixture, 0);
+ expect(input.form).toBe(form);
+ expect(pressEnter(input).defaultPrevented).toBe(true);
+ });
+
+ it('should prevent implicit submission on Enter in the advanced filtering dialog opened with custom overlay settings', async () => {
+ grid.openAdvancedFilteringDialog({
+ closeOnOutsideClick: false,
+ modal: false,
+ positionStrategy: new GlobalPositionStrategy(),
+ scrollStrategy: new AbsoluteScrollStrategy()
+ });
+ await fixture.whenStable();
+ fixture.detectChanges();
+
+ const input = await addAdvancedFilteringCondition(fixture);
+ expect(grid.nativeElement.contains(input)).toBe(false);
+ expect(input.form).toBe(form);
+ expect(pressEnter(input).defaultPrevented).toBe(true);
+
+ grid.closeAdvancedFilteringDialog(false);
+ await fixture.whenStable();
+ });
+
+ it('should not submit the form on Enter in a filtering row date picker calendar, which moves the focus to its input', async () => {
+ GridFunctions.clickFilterCellChipUI(fixture, 'Released');
+ await fixture.whenStable();
+ fixture.detectChanges();
+
+ const filteringRow = fixture.debugElement.query(By.css(FILTER_UI_ROW));
+ const datePicker = filteringRow.query(By.directive(IgxDatePickerComponent)).componentInstance as IgxDatePickerComponent;
+ const opened = firstValueFrom(datePicker.opened);
+ (datePicker.getEditElement() as HTMLElement).click();
+ fixture.detectChanges();
+ await opened;
+ await fixture.whenStable();
+ fixture.detectChanges();
+ expect(document.activeElement!.closest('igx-calendar')).not.toBeNull();
+
+ await userEvent.keyboard('{Enter}');
+ await fixture.whenStable();
+ fixture.detectChanges();
+
+ expect(datePicker.collapsed).toBe(true);
+ expect((document.activeElement as HTMLInputElement).form).toBe(form);
+ expect(fixture.componentInstance.submits).toBe(0);
+ });
+
+ it('should submit the form on Enter in an input outside the grid', async () => {
+ await userEvent.click(fixture.nativeElement.querySelector('#outerInput'));
+ await userEvent.keyboard('{Enter}');
+ expect(fixture.componentInstance.submits).toBe(1);
+ });
+
+ it('should not prevent the native Enter behavior of other elements inside the grid', () => {
+ const fileInput = grid.nativeElement.querySelector('input[type=file]') as HTMLInputElement;
+ expect(fileInput.form).toBe(form);
+
+ expect(pressEnter(grid.nativeElement.querySelector('summary')!).defaultPrevented).toBe(false);
+ expect(pressEnter(fileInput).defaultPrevented).toBe(false);
+ expect(pressEnter(grid.nativeElement.querySelector('input[type=color]')!).defaultPrevented).toBe(false);
+ });
+});
+
+describe('IgxGrid - implicit form submission from grid components outside of the grid #grid', () => {
+ let fixture: ComponentFixture;
+ let form: HTMLFormElement;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [NoopAnimationsModule, GridComponentsInFormComponent]
+ }).compileComponents();
+ });
+
+ beforeEach(async () => {
+ fixture = TestBed.createComponent(GridComponentsInFormComponent);
+ fixture.detectChanges();
+ await fixture.whenStable();
+ fixture.detectChanges();
+ form = fixture.nativeElement.querySelector('form');
+ });
+
+ it('should prevent implicit submission on Enter in the standalone column actions filter input', () => {
+ const input: HTMLInputElement = fixture.nativeElement.querySelector('#standaloneActions input');
+ expect(fixture.componentInstance.grid.nativeElement.contains(input)).toBe(false);
+ expect(input.form).toBe(form);
+ expect(pressEnter(input).defaultPrevented).toBe(true);
+ });
+});
+
+@Component({
+ template: `
+ `,
+ changeDetection: ChangeDetectionStrategy.Eager,
+ imports: [
+ IgxGridComponent,
+ IgxColumnComponent,
+ IgxCellTemplateDirective,
+ IgxGridToolbarComponent,
+ IgxGridToolbarActionsComponent,
+ IgxGridToolbarHidingComponent
+ ]
+})
+class GridInFormComponent {
+ @ViewChild('grid', { static: true })
+ public grid!: IgxGridComponent;
+
+ public data = DATA;
+ public submits = 0;
+}
+
+@Component({
+ template: `
+ `,
+ changeDetection: ChangeDetectionStrategy.Eager,
+ imports: [
+ IgxGridComponent,
+ IgxColumnComponent,
+ IgxColumnActionsComponent,
+ IgxColumnHidingDirective
+ ]
+})
+class GridComponentsInFormComponent {
+ @ViewChild('grid', { static: true })
+ public grid!: IgxGridComponent;
+
+ public data = DATA;
+}
diff --git a/projects/igniteui-angular/grids/pivot-grid/src/pivot-data-selector.component.html b/projects/igniteui-angular/grids/pivot-grid/src/pivot-data-selector.component.html
index 6323dd02a2e..af95f530c3a 100644
--- a/projects/igniteui-angular/grids/pivot-grid/src/pivot-data-selector.component.html
+++ b/projects/igniteui-angular/grids/pivot-grid/src/pivot-data-selector.component.html
@@ -7,6 +7,7 @@
tabindex="0"
placeholder="Search"
autocomplete="off"
+ (keydown)="preventImplicitSubmission($event)"
/>
diff --git a/projects/igniteui-angular/grids/pivot-grid/src/pivot-data-selector.component.ts b/projects/igniteui-angular/grids/pivot-grid/src/pivot-data-selector.component.ts
index 901c7a05377..10fbd441074 100644
--- a/projects/igniteui-angular/grids/pivot-grid/src/pivot-data-selector.component.ts
+++ b/projects/igniteui-angular/grids/pivot-grid/src/pivot-data-selector.component.ts
@@ -25,7 +25,7 @@ import { IgxExpansionPanelBodyComponent, IgxExpansionPanelComponent, IgxExpansio
import { IDragBaseEventArgs, IDragGhostBaseEventArgs, IDragMoveEventArgs, IDropBaseEventArgs, IDropDroppedEventArgs, IgxDragDirective, IgxDragHandleDirective, IgxDropDirective } from 'igniteui-angular/directives';
import { IgxChipComponent } from 'igniteui-angular/chips';
import { IgxDropDownComponent, IgxDropDownItemComponent, IgxDropDownItemNavigationDirective, ISelectionEventArgs } from 'igniteui-angular/drop-down';
-import { AbsoluteScrollStrategy, AutoPositionStrategy, ColumnType, OverlaySettings, PositionSettings, ɵSize, SortingDirection, VerticalAlignment } from 'igniteui-angular/core';
+import { AbsoluteScrollStrategy, AutoPositionStrategy, ColumnType, OverlaySettings, PositionSettings, preventImplicitSubmission, ɵSize, SortingDirection, VerticalAlignment } from 'igniteui-angular/core';
import { IPivotAggregator, IPivotDimension, IPivotValue, PivotDimensionType, PivotGridType, PivotUtil } from 'igniteui-angular/grids/core';
import { Subscription } from 'rxjs';
@@ -77,6 +77,8 @@ export class IgxPivotDataSelectorComponent implements OnDestroy {
private pivotConfigChangeSub?: Subscription;
protected pipeRetrigger = 0;
+ protected readonly preventImplicitSubmission = preventImplicitSubmission;
+
/**
* Gets/sets whether the columns panel is expanded
diff --git a/projects/igniteui-angular/grids/pivot-grid/src/pivot-data-selector.spec.ts b/projects/igniteui-angular/grids/pivot-grid/src/pivot-data-selector.spec.ts
index 81d929cb1e0..bbd55e819d8 100644
--- a/projects/igniteui-angular/grids/pivot-grid/src/pivot-data-selector.spec.ts
+++ b/projects/igniteui-angular/grids/pivot-grid/src/pivot-data-selector.spec.ts
@@ -44,6 +44,27 @@ describe("Pivot data selector #pivotGrid", () => {
expect(selector.dims).toEqual([]);
expect(selector.values).toEqual([]);
});
+
+ it("should prevent implicit form submission on Enter in its search input", () => {
+ const fixture = TestBed.createComponent(IgxPivotDataSelectorComponent);
+ fixture.detectChanges();
+
+ const input = fixture.debugElement.query(By.directive(IgxInputDirective)).nativeElement as HTMLInputElement;
+ const pressEnter = () => {
+ const event = new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, cancelable: true });
+ input.dispatchEvent(event);
+ return event.defaultPrevented;
+ };
+
+ expect(pressEnter()).toBe(false);
+
+ const form = document.createElement('form');
+ fixture.nativeElement.parentElement.appendChild(form);
+ form.appendChild(fixture.nativeElement);
+ expect(input.form).toBe(form);
+ expect(pressEnter()).toBe(true);
+ form.remove();
+ });
});
describe("Pivot data selector integration #pivotGrid", () => {
diff --git a/projects/igniteui-angular/query-builder/src/query-builder/query-builder-tree.component.html b/projects/igniteui-angular/query-builder/src/query-builder/query-builder-tree.component.html
index 9c3b216eec2..1c28f5f9948 100644
--- a/projects/igniteui-angular/query-builder/src/query-builder/query-builder-tree.component.html
+++ b/projects/igniteui-angular/query-builder/src/query-builder/query-builder-tree.component.html
@@ -333,6 +333,7 @@