mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-15 01:03:03 +08:00
fix(reorder-group): add children fallback for framework compatibility (#30593)
Issue number: resolves #30592 --------- ## What is the current behavior? Reorder group is failing for Angular, React & Vue due to the change from `children` to `__children`. ## What is the new behavior? - Fallback to `children` if `__children` is undefined. - Adds an e2e test for Angular (depends on https://github.com/ionic-team/ionic-framework/pull/30594) - Tasks have been created to migrate and add e2e tests for the other frameworks ## Does this introduce a breaking change? - [ ] Yes - [x] No ## Other information Dev build: `8.7.2-dev.11754087334.1815cf22` --------- Co-authored-by: Brandy Smith <6577830+brandyscarney@users.noreply.github.com>
This commit is contained in:
@ -153,7 +153,7 @@ export class ReorderGroup implements ComponentInterface {
|
|||||||
const heights = this.cachedHeights;
|
const heights = this.cachedHeights;
|
||||||
heights.length = 0;
|
heights.length = 0;
|
||||||
const el = this.el;
|
const el = this.el;
|
||||||
const children: any = el.__children;
|
const children: any = el.__children || el.children;
|
||||||
if (!children || children.length === 0) {
|
if (!children || children.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -259,7 +259,7 @@ export class ReorderGroup implements ComponentInterface {
|
|||||||
private completeReorder(listOrReorder?: boolean | any[]): any {
|
private completeReorder(listOrReorder?: boolean | any[]): any {
|
||||||
const selectedItemEl = this.selectedItemEl;
|
const selectedItemEl = this.selectedItemEl;
|
||||||
if (selectedItemEl && this.state === ReorderGroupState.Complete) {
|
if (selectedItemEl && this.state === ReorderGroupState.Complete) {
|
||||||
const children: any = this.el.__children;
|
const children: any = this.el.__children || this.el.children;
|
||||||
const len = children.length;
|
const len = children.length;
|
||||||
const toIndex = this.lastToIndex;
|
const toIndex = this.lastToIndex;
|
||||||
const fromIndex = indexForItem(selectedItemEl);
|
const fromIndex = indexForItem(selectedItemEl);
|
||||||
@ -309,7 +309,7 @@ export class ReorderGroup implements ComponentInterface {
|
|||||||
/********* DOM WRITE ********* */
|
/********* DOM WRITE ********* */
|
||||||
private reorderMove(fromIndex: number, toIndex: number) {
|
private reorderMove(fromIndex: number, toIndex: number) {
|
||||||
const itemHeight = this.selectedItemHeight;
|
const itemHeight = this.selectedItemHeight;
|
||||||
const children: any = this.el.__children;
|
const children: any = this.el.__children || this.el.children;
|
||||||
for (let i = 0; i < children.length; i++) {
|
for (let i = 0; i < children.length; i++) {
|
||||||
const style = (children[i] as any).style;
|
const style = (children[i] as any).style;
|
||||||
let value = '';
|
let value = '';
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
import { expect } from '@playwright/test';
|
||||||
|
import { test } from '@playwright/test';
|
||||||
|
import { dragElementBy } from '../../utils/drag-utils';
|
||||||
|
|
||||||
|
test.describe('reorder-group: angular standalone', () => {
|
||||||
|
test('should reorder the items', async ({ page }) => {
|
||||||
|
await page.goto('/standalone/reorder-group');
|
||||||
|
|
||||||
|
// Get initial order
|
||||||
|
const initialItems = await page.locator('ion-item').allTextContents();
|
||||||
|
expect(initialItems).toEqual(['Item 1', 'Item 2', 'Item 3']);
|
||||||
|
|
||||||
|
const reorderGroup = page.locator('ion-reorder-group');
|
||||||
|
|
||||||
|
// Drag the first item down to move it to the end (below Item 3)
|
||||||
|
await dragElementBy(reorderGroup.locator('ion-reorder').first(), page, 0, 300);
|
||||||
|
|
||||||
|
// Wait for the reorder to complete
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
|
||||||
|
// Verify the new order - Item 1 should now be at the end
|
||||||
|
const finalItems = await page.locator('ion-item').allTextContents();
|
||||||
|
expect(finalItems).toEqual(['Item 2', 'Item 3', 'Item 1']);
|
||||||
|
});
|
||||||
|
});
|
@ -19,6 +19,7 @@ export const routes: Routes = [
|
|||||||
{ path: 'providers', loadComponent: () => import('../providers/providers.component').then(c => c.ProvidersComponent) },
|
{ path: 'providers', loadComponent: () => import('../providers/providers.component').then(c => c.ProvidersComponent) },
|
||||||
{ path: 'overlay-controllers', loadComponent: () => import('../overlay-controllers/overlay-controllers.component').then(c => c.OverlayControllersComponent) },
|
{ path: 'overlay-controllers', loadComponent: () => import('../overlay-controllers/overlay-controllers.component').then(c => c.OverlayControllersComponent) },
|
||||||
{ path: 'button', loadComponent: () => import('../button/button.component').then(c => c.ButtonComponent) },
|
{ path: 'button', loadComponent: () => import('../button/button.component').then(c => c.ButtonComponent) },
|
||||||
|
{ path: 'reorder-group', loadComponent: () => import('../reorder-group/reorder-group.component').then(c => c.ReorderGroupComponent) },
|
||||||
{ path: 'icon', loadComponent: () => import('../icon/icon.component').then(c => c.IconComponent) },
|
{ path: 'icon', loadComponent: () => import('../icon/icon.component').then(c => c.IconComponent) },
|
||||||
{ path: 'split-pane', redirectTo: '/standalone/split-pane/inbox', pathMatch: 'full' },
|
{ path: 'split-pane', redirectTo: '/standalone/split-pane/inbox', pathMatch: 'full' },
|
||||||
{
|
{
|
||||||
|
@ -28,6 +28,11 @@
|
|||||||
Icon Test
|
Icon Test
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
<ion-item routerLink="/standalone/reorder-group">
|
||||||
|
<ion-label>
|
||||||
|
Reorder Group Test
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
</ion-list>
|
</ion-list>
|
||||||
|
|
||||||
<ion-list>
|
<ion-list>
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
import { Component } from "@angular/core";
|
||||||
|
import { IonItem, IonLabel, IonReorder, IonReorderGroup } from '@ionic/angular/standalone';
|
||||||
|
import { ReorderEndCustomEvent } from "@ionic/angular";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-reorder-group',
|
||||||
|
template: `
|
||||||
|
<ion-reorder-group disabled="false" (ionReorderEnd)="onReorderEnd($event)">
|
||||||
|
<ion-item>
|
||||||
|
<ion-reorder slot="end"></ion-reorder>
|
||||||
|
<ion-label>Item 1</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item>
|
||||||
|
<ion-reorder slot="end"></ion-reorder>
|
||||||
|
<ion-label>Item 2</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item>
|
||||||
|
<ion-reorder slot="end"></ion-reorder>
|
||||||
|
<ion-label>Item 3</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-reorder-group>
|
||||||
|
`,
|
||||||
|
standalone: true,
|
||||||
|
imports: [IonItem, IonLabel, IonReorder, IonReorderGroup]
|
||||||
|
})
|
||||||
|
export class ReorderGroupComponent {
|
||||||
|
onReorderEnd(event: ReorderEndCustomEvent) {
|
||||||
|
if (event.detail.from !== event.detail.to) {
|
||||||
|
console.log('ionReorderEnd: Dragged from index', event.detail.from, 'to', event.detail.to);
|
||||||
|
} else {
|
||||||
|
console.log('ionReorderEnd: No position change occurred');
|
||||||
|
}
|
||||||
|
|
||||||
|
event.detail.complete();
|
||||||
|
}
|
||||||
|
}
|
@ -36,6 +36,7 @@ import IonPopoverNested from './pages/overlay-components/IonPopoverNested';
|
|||||||
import KeepContentsMounted from './pages/overlay-components/KeepContentsMounted';
|
import KeepContentsMounted from './pages/overlay-components/KeepContentsMounted';
|
||||||
import OverlayComponents from './pages/overlay-components/OverlayComponents';
|
import OverlayComponents from './pages/overlay-components/OverlayComponents';
|
||||||
import OverlayHooks from './pages/overlay-hooks/OverlayHooks';
|
import OverlayHooks from './pages/overlay-hooks/OverlayHooks';
|
||||||
|
import ReorderGroup from './pages/ReorderGroup';
|
||||||
|
|
||||||
setupIonicReact();
|
setupIonicReact();
|
||||||
|
|
||||||
@ -67,6 +68,7 @@ const App: React.FC = () => (
|
|||||||
<Route path="/tabs-direct-navigation" component={TabsDirectNavigation} />
|
<Route path="/tabs-direct-navigation" component={TabsDirectNavigation} />
|
||||||
<Route path="/icons" component={Icons} />
|
<Route path="/icons" component={Icons} />
|
||||||
<Route path="/inputs" component={Inputs} />
|
<Route path="/inputs" component={Inputs} />
|
||||||
|
<Route path="/reorder-group" component={ReorderGroup} />
|
||||||
</IonRouterOutlet>
|
</IonRouterOutlet>
|
||||||
</IonReactRouter>
|
</IonReactRouter>
|
||||||
</IonApp>
|
</IonApp>
|
||||||
|
@ -46,6 +46,9 @@ const Main: React.FC<MainProps> = () => {
|
|||||||
<IonItem routerLink="/inputs">
|
<IonItem routerLink="/inputs">
|
||||||
<IonLabel>Inputs</IonLabel>
|
<IonLabel>Inputs</IonLabel>
|
||||||
</IonItem>
|
</IonItem>
|
||||||
|
<IonItem routerLink="/reorder-group">
|
||||||
|
<IonLabel>Reorder Group</IonLabel>
|
||||||
|
</IonItem>
|
||||||
</IonList>
|
</IonList>
|
||||||
</IonContent>
|
</IonContent>
|
||||||
</IonPage>
|
</IonPage>
|
||||||
|
58
packages/react/test/base/src/pages/ReorderGroup.tsx
Normal file
58
packages/react/test/base/src/pages/ReorderGroup.tsx
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
IonBackButton,
|
||||||
|
IonButtons,
|
||||||
|
IonContent,
|
||||||
|
IonHeader,
|
||||||
|
IonItem,
|
||||||
|
IonLabel,
|
||||||
|
IonPage,
|
||||||
|
IonReorder,
|
||||||
|
IonReorderGroup,
|
||||||
|
IonTitle,
|
||||||
|
IonToolbar,
|
||||||
|
} from '@ionic/react';
|
||||||
|
import type { ReorderEndCustomEvent } from '@ionic/react';
|
||||||
|
|
||||||
|
const ReorderGroup: React.FC = () => {
|
||||||
|
const onReorderEnd = (event: ReorderEndCustomEvent) => {
|
||||||
|
if (event.detail.from !== event.detail.to) {
|
||||||
|
console.log('ionReorderEnd: Dragged from index', event.detail.from, 'to', event.detail.to);
|
||||||
|
} else {
|
||||||
|
console.log('ionReorderEnd: No position change occurred');
|
||||||
|
}
|
||||||
|
|
||||||
|
event.detail.complete();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IonPage>
|
||||||
|
<IonHeader>
|
||||||
|
<IonToolbar>
|
||||||
|
<IonButtons slot="start">
|
||||||
|
<IonBackButton></IonBackButton>
|
||||||
|
</IonButtons>
|
||||||
|
<IonTitle>Reorder Group</IonTitle>
|
||||||
|
</IonToolbar>
|
||||||
|
</IonHeader>
|
||||||
|
<IonContent>
|
||||||
|
<IonReorderGroup disabled={false} onIonReorderEnd={onReorderEnd}>
|
||||||
|
<IonItem>
|
||||||
|
<IonReorder slot="end"></IonReorder>
|
||||||
|
<IonLabel>Item 1</IonLabel>
|
||||||
|
</IonItem>
|
||||||
|
<IonItem>
|
||||||
|
<IonReorder slot="end"></IonReorder>
|
||||||
|
<IonLabel>Item 2</IonLabel>
|
||||||
|
</IonItem>
|
||||||
|
<IonItem>
|
||||||
|
<IonReorder slot="end"></IonReorder>
|
||||||
|
<IonLabel>Item 3</IonLabel>
|
||||||
|
</IonItem>
|
||||||
|
</IonReorderGroup>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ReorderGroup;
|
@ -86,6 +86,10 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
path: '/components/range',
|
path: '/components/range',
|
||||||
component: () => import('@/views/Range.vue')
|
component: () => import('@/views/Range.vue')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/reorder-group',
|
||||||
|
component: () => import('@/views/ReorderGroup.vue')
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/nested',
|
path: '/nested',
|
||||||
component: () => import('@/views/RouterOutlet.vue'),
|
component: () => import('@/views/RouterOutlet.vue'),
|
||||||
|
@ -29,6 +29,9 @@
|
|||||||
<ion-item router-link="/navigation" id="navigation">
|
<ion-item router-link="/navigation" id="navigation">
|
||||||
<ion-label>Navigation</ion-label>
|
<ion-label>Navigation</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
<ion-item router-link="/reorder-group">
|
||||||
|
<ion-label>Reorder Group</ion-label>
|
||||||
|
</ion-item>
|
||||||
<ion-item router-link="/routing" id="routing">
|
<ion-item router-link="/routing" id="routing">
|
||||||
<ion-label>Routing</ion-label>
|
<ion-label>Routing</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
78
packages/vue/test/base/src/views/ReorderGroup.vue
Normal file
78
packages/vue/test/base/src/views/ReorderGroup.vue
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<template>
|
||||||
|
<ion-page>
|
||||||
|
<ion-header :translucent="true">
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-buttons slot="start">
|
||||||
|
<ion-back-button></ion-back-button>
|
||||||
|
</ion-buttons>
|
||||||
|
<ion-title>Reorder Group</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
|
||||||
|
<ion-content :fullscreen="true">
|
||||||
|
<ion-reorder-group :disabled="false" @ion-reorder-end="onReorderEnd">
|
||||||
|
<ion-item>
|
||||||
|
<ion-reorder slot="end"></ion-reorder>
|
||||||
|
<ion-label>Item 1</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item>
|
||||||
|
<ion-reorder slot="end"></ion-reorder>
|
||||||
|
<ion-label>Item 2</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item>
|
||||||
|
<ion-reorder slot="end"></ion-reorder>
|
||||||
|
<ion-label>Item 3</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-reorder-group>
|
||||||
|
</ion-content>
|
||||||
|
</ion-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import {
|
||||||
|
IonButtons,
|
||||||
|
IonBackButton,
|
||||||
|
IonContent,
|
||||||
|
IonHeader,
|
||||||
|
IonItem,
|
||||||
|
IonLabel,
|
||||||
|
IonPage,
|
||||||
|
IonReorder,
|
||||||
|
IonReorderGroup,
|
||||||
|
IonTitle,
|
||||||
|
IonToolbar,
|
||||||
|
} from "@ionic/vue";
|
||||||
|
import { defineComponent } from "vue";
|
||||||
|
import type { ReorderEndCustomEvent } from "@ionic/vue";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
IonButtons,
|
||||||
|
IonBackButton,
|
||||||
|
IonContent,
|
||||||
|
IonHeader,
|
||||||
|
IonItem,
|
||||||
|
IonLabel,
|
||||||
|
IonPage,
|
||||||
|
IonReorder,
|
||||||
|
IonReorderGroup,
|
||||||
|
IonTitle,
|
||||||
|
IonToolbar,
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
const onReorderEnd = (event: ReorderEndCustomEvent) => {
|
||||||
|
if (event.detail.from !== event.detail.to) {
|
||||||
|
console.log('ionReorderEnd: Dragged from index', event.detail.from, 'to', event.detail.to);
|
||||||
|
} else {
|
||||||
|
console.log('ionReorderEnd: No position change occurred');
|
||||||
|
}
|
||||||
|
|
||||||
|
event.detail.complete();
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
onReorderEnd,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
Reference in New Issue
Block a user