feat: improve performance when using ion-item-sliding
See original GitHub issueFeature Request
Ionic version:
[x] 5.x
Describe the Feature Request
When rendering lists of items with complex structures including ion-item-sliding
and ion-item-options
, DOM rendering can be incredibly expensive. This is exacerbated on mobile devices with weaker G/CPUs and less memory where rendering performance is generally slow.
It is not currently a “supported feature” to show the contents of items dynamically when sliding begins, then hide them again when sliding ends, to keep DOM node count and initial render under control.
Additionally, this makes it difficult to create custom components that use ion-item-sliding
and insert slotted content into ion-item-options
elements, or even insert their own, conditionally via ng-content
or a similar composition technique.
There are a few problems that get in the way of this:
- Lack of observable or event that would notify strictly on item is open or not (boolean). This can be done using the
(ionDrag)
event, but it’s a bit painful. - Width of
options-start/end
is calculated at initial render time. If items are added/removed conditionally from these slots using*ngIf
or the like, the window for which the sliding item will open does not adjust its width. Therefore when the item is slid open, then elements are rendered (fade in animation to make it nice), the item will snap closed again because it does not believe there is anything to show. - The sliding animation is jittery on many devices (seems mostly chromium based issue) which can lead to strange gestures and things snapping closed again while dragging.
Describe Preferred Solution
ion-item-sliding
should:
- Publish an observable or event emitter that simply reports “am I open or not”.
- Width of items should be calculated before and after
(ionDrag)
has been started. If new elements have been added, the width should be adjusted. AContentObserver
comes to mind so that a fixed-width pre-rendered placeholder is not required.
Describe Alternatives
Basically hack this in and implement it manually, which is complex and difficult to get right due to the need to set a fixed width to a placeholder element inside the ion-item-options
component so that once sliding starts, the item will know it has contents, set a width, and stay open/not snap closed again.
Related Code
<ion-item-options *ngIf="state.isSlidingEnabled" [hidden]=disabled #optionsEnd class="animate-fade-in">
<ng-container slot="options-end">
<ng-container *ngIf="state.sliderOpen; else placeholderTemplate">
<ng-container *ngIf="sliderOpen">
<!-- Actual contents we want dynamically rendered -->
<ion-item-option color="transparent"
(tap)="item.toggleSlider()">
<ion-icon slot=top name="chevron-forward">
</ion-icon>
</ion-item-option>
</ng-container>
<ng-template #placeholderTemplate>
<div style="width: 185px"> <!-- Fixed width placeholder -->
</div>
</ng-template>
...
</ion-item-options>
Additional Context
Issue Analytics
- State:
- Created 2 years ago
- Reactions:3
- Comments:32 (10 by maintainers)
Top GitHub Comments
I hope bumping this is OK since I’m thinking this may have gotten lost in the mix (no longer labeled for v6.x / part of the milestone). Just checking in. Feel free to ignore.
Agreed. I appreciate all the clarifying information you have given!