components
components copied to clipboard
CDKDragAndDrop: Collapse cdkDropList item contents on cdkDragStarted event
(Marked as troubleshooting since I wasn't sure if there was a known solution for this case)
What are you trying to do?
Collapse/hide the contents of all items in a cdkDropList upon starting a drag event, leaving a condensed view of labels that is easier to sort.
What troubleshooting steps have you tried?
When starting the drag event, all items collapse except for the item currently being dragged, causing issues in the list placeholder when attempting to drop an item. Once the drop event is complete, the dropped item collapses and the list returns to normal.
Reproduction
StackBlitz: https://stackblitz.com/edit/components-issue-bt4kvt?file=app%2Fapp.component.ts
Steps to reproduce:
- Set up a cdkDropList with items that contain a title and collapsible content panel.
- Set the cdkDragStarted event for the list items to collapse all of the content panels.
- Make sure all items in the list are expanded.
- Begin dragging one of the items.
Environment
- Angular: 8.2.0
- CDK/Material: 8.2.3
- Browser(s): Chrome
- Operating System (e.g. Windows, macOS, Ubuntu): Windows
Im trying only collapse the item that has dragged and i have the same result, it only collapse the list after drop, not when drag started.
Issue still persists in material v11.2.2. If someone is interested in a workaround:
Steps:
- On drag start set some classname on all list items which would hide content you don't need on drag through css. For example, we left only header visible, and set
display: nonefor everything else. Something like that:
public dragStart({ children }: HTMLOListElement): void {
for (let i = 0; i < children.length; i++) {
children[i].classList.add('cdk-drag-collapsed-item');
}
}
- Remove that classname with same approach on drop/release/drag end (whenever you want) to expand items back.
Vanilla JS classList used to avoid change-detection to run (which could cause performance drop for a few moments and also could require some additional workaround steps).
However, in some cases it still may look/feel buggy, so official fix would be really nice to have.
UPDATE: "I don’t think it’s beneficial to collapse groups automatically when the user starts dragging a row. That would interrupt the user’s action by moving everything around while he’s trying to interact with it, creating a moving target. To mitigate that problem somewhat, you could require that the user enter a reorder mode (similar to what you might be familiar with in iOS) in which groups are collapsed." (https://ux.stackexchange.com/a/82524)
This issue is still important
Up. Our current workaround:
To call expandDraggableListItems on cdkDragStart
To call collapseDraggableListItems on cdkDragEnd
export abstract class DragDropUtils {
private static _listDraggingClassName = 'pl-drop-list-dragging';
// Workaround due to draggable content not collapsing on drag issue: https://github.com/angular/components/issues/18179
public static expandDraggableListItems(dropList: HTMLElement): void {
dropList.style.paddingBottom = '';
dropList.classList.remove(DragDropUtils._listDraggingClassName);
}
// Workaround due to draggable content not collapsing on drag issue: https://github.com/angular/components/issues/18179
public static collapseDraggableListItems(dropList: HTMLElement): void {
const childrenArray = Array.from(dropList.children) as HTMLElement[];
let initialHeightSum = 0;
let updatedHeightSum = 0;
for (const child of childrenArray) {
initialHeightSum += child.offsetHeight;
}
dropList.classList.add(DragDropUtils._listDraggingClassName);
for (const child of childrenArray) {
updatedHeightSum += child.offsetHeight;
}
dropList.style.paddingBottom = `${initialHeightSum - updatedHeightSum}px`;
}
}