diff --git a/packages/devextreme/js/__internal/ui/collection/hierarchical.ts b/packages/devextreme/js/__internal/ui/collection/hierarchical.ts index 5de8fd5a0b06..79f01834fb87 100644 --- a/packages/devextreme/js/__internal/ui/collection/hierarchical.ts +++ b/packages/devextreme/js/__internal/ui/collection/hierarchical.ts @@ -3,7 +3,7 @@ import type { ItemLike } from '@js/ui/collection/ui.collection_widget.base'; import type { HierarchicalCollectionWidgetOptions } from '@js/ui/hierarchical_collection/ui.hierarchical_collection_widget'; import HierarchicalCollectionWidget from '@js/ui/hierarchical_collection/ui.hierarchical_collection_widget'; -import CollectionWidgetEdit from './edit'; +import AsyncCollectionWidget from './async'; export interface TypedCollectionWidgetOptions< // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -22,7 +22,7 @@ declare class Hierarchical< TItem extends ItemLike = any, // eslint-disable-next-line @typescript-eslint/no-explicit-any TKey = any, -> extends CollectionWidgetEdit { +> extends AsyncCollectionWidget { // eslint-disable-next-line @typescript-eslint/no-explicit-any _dataAdapter?: any; diff --git a/packages/devextreme/js/__internal/ui/context_menu/m_context_menu.ts b/packages/devextreme/js/__internal/ui/context_menu/m_context_menu.ts index 30c11c7f6906..4ee19298ecf9 100644 --- a/packages/devextreme/js/__internal/ui/context_menu/m_context_menu.ts +++ b/packages/devextreme/js/__internal/ui/context_menu/m_context_menu.ts @@ -531,6 +531,7 @@ class ContextMenu extends MenuBase { _renderSubmenuItems(node, $itemFrame: dxElementWrapper): void { this._renderItems(this._getChildNodes(node), $itemFrame); + this._planPostRenderActions(); const $submenu = $itemFrame.children(`.${DX_SUBMENU_CLASS}`); @@ -704,7 +705,7 @@ class ContextMenu extends MenuBase { return availableHeight - SUBMENU_PADDING; } - _dimensionChanged() { + _dimensionChanged(showAnimation = true) { if (!this._shownSubmenus) { return; } @@ -715,8 +716,10 @@ class ContextMenu extends MenuBase { this._setSubMenuHeight($submenu, $item, true); this._scrollToElement($item); - const submenuPosition = this._getSubmenuPosition($item); - animationPosition.setup($submenu, submenuPosition); + if (showAnimation) { + const submenuPosition = this._getSubmenuPosition($item); + animationPosition.setup($submenu, submenuPosition); + } }); } @@ -1130,6 +1133,10 @@ class ContextMenu extends MenuBase { hide(): Promise { return this.toggle(false); } + + _postProcessRenderItems() { + this._dimensionChanged(false); + } } // @ts-expect-error diff --git a/packages/devextreme/js/__internal/ui/hierarchical_collection/m_hierarchical_collection_widget.ts b/packages/devextreme/js/__internal/ui/hierarchical_collection/m_hierarchical_collection_widget.ts index 6deddad62d6d..9d894e8ddfb5 100644 --- a/packages/devextreme/js/__internal/ui/hierarchical_collection/m_hierarchical_collection_widget.ts +++ b/packages/devextreme/js/__internal/ui/hierarchical_collection/m_hierarchical_collection_widget.ts @@ -7,7 +7,7 @@ import { extend } from '@js/core/utils/extend'; import { getImageContainer } from '@js/core/utils/icon'; import { each } from '@js/core/utils/iterator'; import { isFunction, isObject } from '@js/core/utils/type'; -import CollectionWidget from '@js/ui/collection/ui.collection_widget.edit'; +import CollectionWidget from '@js/ui/collection/ui.collection_widget.async'; import HierarchicalDataAdapter from './m_data_adapter'; diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets/contextMenu.async.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets/contextMenu.async.tests.js index a31b99b7b069..b88e73d65101 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets/contextMenu.async.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets/contextMenu.async.tests.js @@ -4,6 +4,13 @@ import ContextMenu from 'ui/context_menu'; import 'ui/button'; import 'generic_light.css!'; +const DX_SUBMENU_CLASS = 'dx-submenu'; +const DX_CONTEXT_MENU_ITEMS_CONTAINER_CLASS = 'dx-menu-items-container'; +const DX_SCROLLABLE_CONTENT_CLASS = 'dx-scrollable-container'; +const DX_MENU_ITEM_CLASS = 'dx-menu-item'; + +const ITEMS_CONTAINER_PADDING = 1; + QUnit.testStart(() => { const markup = '\
\ @@ -60,5 +67,59 @@ QUnit.module('Context menu', () => { assert.strictEqual(instance.option('items').length, 2, 'items.length'); }); + + QUnit.test('Context menu should have correct height on async render (T1258881)', function(assert) { + const done = assert.async(); + + const menuTargetSelector = '#menuTarget'; + const items = [{ + text: 'root', + items: [ + { text: 'sub 1', template: 'myTemplate' }, + { text: 'sub 2', template: 'myTemplate' }, + { text: 'sub 3', template: 'myTemplate' }, + { text: 'sub 4', template: 'myTemplate' }, + { text: 'sub 5', template: 'myTemplate' }, + { text: 'sub 6', template: 'myTemplate' }, + { text: 'sub 7', template: 'myTemplate' }, + ] + }]; + + const instance = new ContextMenu($('#simpleMenu'), { + target: menuTargetSelector, + items, + templatesRenderAsynchronously: true, + itemTemplate: 'myTemplate', + integrationOptions: { + templates: { + myTemplate: { + render({ model, container, onRendered }) { + setTimeout(() => { + container.append($('
').text(model.text)); + onRendered(); + }); + } + } + } + }, + }); + + $(menuTargetSelector).trigger($.Event('dxcontextmenu')); + + const $itemsContainer = instance.itemsContainer(); + const $rootItem = $itemsContainer.find(`.${DX_MENU_ITEM_CLASS}`).eq(0); + $($itemsContainer).trigger($.Event('dxhoverstart', { target: $rootItem.get(0) })); + + instance.option('onShown', (e) => { + const $submenus = $(`.${DX_SUBMENU_CLASS}`); + const $nestedSubmenu = $submenus.eq(1); + const $nestedSubmenuItemsContainer = $nestedSubmenu.find(`.${DX_CONTEXT_MENU_ITEMS_CONTAINER_CLASS}`); + const $scrollableContainer = $nestedSubmenu.find(`.${DX_SCROLLABLE_CONTENT_CLASS}`); + + assert.roughEqual($nestedSubmenuItemsContainer.outerHeight(), $scrollableContainer.outerHeight(), .1); + done(); + }); + + }); });