Issue
I’m trying to use ion-reorder to reorder some items in a page. These item are organized in groups, so a group has several items. I want to organize these items inside the group, but more importantly I want to be able to change the item from a group to another.
I’m facing 2 problems currently:
- I can’t update the array, consequently the item orders are not show correctly when changed.
- I can’t move a item outside it’s group, consequently I can’t move to another group.
html
<ion-content>
<ion-list *ngFor='let group of groupArray'>
<ion-reorder-group (ionItemReorder)="doReorder($event)" disabled="false">
<ion-list-header>{{group.name}}</ion-list-header>
<ion-item *ngFor='let item of group.items'>
<ion-reorder slot="start"></ion-reorder>
<ion-label>
{{item.name}}
</ion-label>
</ion-item>
</ion-reorder-group>
</ion-list>
</ion-content>
typescript
interface Item {
id: number,
name: string
}
interface Group {
name: string,
items: Item[]
}
interface GroupArray extends Array<Group>{}
...
private groupArray: GroupArray = [
{
name: 'FirstGroup',
items: [
{
id: 1,
name: 'FirstItem'
},{
id: 2,
name: 'SecondItem'
},{
id: 3,
name: 'ThirdItem'
}
]
},
{
name: 'SecondGroup',
items: [
{
id: 4,
name: 'FourthItem'
},{
id: 5,
name: 'FifthItem'
},{
id: 6,
name: 'SixthItem'
}
]
}
];
/** Reorder */
doReorder(ev: CustomEvent<ItemReorderEventDetail>) {
this.groupArray = ev.detail.complete(this.groupArray);
}
I tried to move the <ion-reorder-group>
to several positions, but this is the only one I managed to move the correct items. If I move up, above <ion-list>
, the whole list becomes draggable and I can’t move the item.
I understand that this is happening because the <ion-reorder-group>
is created 2 times, but I can’t think in a way to create only one time and maintain the same aspect, which is exactly like the documentation page that I linked. The difference is that in there they load the items individually, and the groups are just another item that can be drag around.
The other problem I believe is related to how complete()
works. Although it expects any[]
as a parameter, I don’t think it was made to support a complex structure, just a simple array.
How can I solve these two problems?
I’m using Ionic 5 with Angular 10
Solution
For the reording issue, you have two things
- You are sending the wrong items to the
complete
function, it should be the rendered items (groupArray[index].items
), not the root object itself (groupArray
). - The
ion-list-header
should be above theion-reorder-group
, so Ionic won’t treat it as a child of theion-reorder-group
and mess up the reording logic for the array.
Even though the example in the attached link for the ion-reorder is using one big ion-reorder-group
and the ion-list-header
to add some list headers, but this won’t work if you need to update the array using the complete
.
You can do something like this to make it work:
doReorder(ev: CustomEvent<ItemReorderEventDetail>, groupId: number) {
let groupToChangeIndex = this.groupArray.findIndex(
group => group.id === groupId
);
this.groupArray[groupToChangeIndex].items = ev.detail.complete(
this.groupArray[groupToChangeIndex].items
);
}
HTML:
<ion-content>
<ion-list *ngFor='let group of groupArray'>
<ion-list-header>{{group.name}}</ion-list-header>
<ion-reorder-group (ionItemReorder)="doReorder($event, group.id)" disabled="false">
<ion-item *ngFor='let item of group.items'>
<ion-reorder slot="start"></ion-reorder>
<ion-label>
{{item.name}}
</ion-label>
</ion-item>
</ion-reorder-group>
</ion-list>
</ion-content>
At the same time, you can’t move an ion-item from one group to another.
What I can think of for handling this issue is to have one big ion-reorder-group
with the ion-list-header
, and do the reording manually. Accessing the target
property from the event that was sent to the doReorder
function, then you can access the children, filter only the ion-item
then reflect the sorting to the array (even though it is a very ugly workaround).
Update
I actually thought of a better solution. You can create a new array that contains all the items flattened. Then when you want to submit you changes, there will be a function that will create the new order for you. You can check the following Stackblitz: https://stackblitz.com/edit/ionic-5-angular-10-start-template-zasssd?file=src/app/tab1/tab1.page.ts
constructor() {
this.allItemsFlattened = this.groupArray.flatMap((group, index) => [
{ isHeader: true, index: index, name: group.name },
...group.items
]);
}
/** Reorder objects in array */
doReorder(ev: CustomEvent<ItemReorderEventDetail>) {
this.allItemsFlattened = ev.detail.complete(this.allItemsFlattened);
}
getRightOrder() {
const rightOrder = this.allItemsFlattened.reduce((accumlator, item) => {
if (item.isHeader) {
const { id, name, ...rest } = this.groupArray[item.index];
accumlator.push({ id, name, items: [] });
} else {
accumlator[accumlator.length - 1].items.push(item);
}
return accumlator;
}, []);
console.log(rightOrder);
}