angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.34k stars 6.74k forks source link

[dragDrop] On strict movement when dropping outside cdkDropList #17351

Open doyeonOh opened 5 years ago

doyeonOh commented 5 years ago

Feature Description

There is one problem with this, because of some action after dragging on cdkDragDrop.

1. Drag the item. 2. Go through the drop zone. 3. Drop outside the drop zone. In the case of dragDrop in angular / cdk, when dropping outside the drop zone, the item moves to the last drop zone where the item was entered. ![cdk](https://user-images.githubusercontent.com/4124275/66533466-f19b3280-eb4d-11e9-8b2d-ab99a3024761.gif) In the dragula, apart from entering the drop zone, it returns to its original state when dropped outside the drop zone. ![dragula](https://user-images.githubusercontent.com/4124275/66533465-f1029c00-eb4d-11e9-9c01-f486d3d53e5b.gif) Therefore, it would be nice to provide an strict method of returning to angular / cdk dragdrop as an option. Please let me know if there is a way around this. thank you
muellerdberlin commented 4 years ago

@doyeonOh how did you solve the issue? did you use different elements than cdk or was it possible to return the element to it's origin list?

muellerdberlin commented 4 years ago

I got a solution: You can use the attribute isPointerOverContainer: true|false of the (cdkDropListDropped)=drop($event) Event.

doyeonOh commented 4 years ago

@muellerdberlin I had to be able to use the private variable _dropContainer of CdkDrag.

However, since typescript does not allow private access, it is solved through @ ts-ignore, which ignores type checking.

I wrote the code by referring to the drag-ref.ts of angular.

Here is the code that worked.

private moveToOriginDropList(cdkDrag: CdkDrag) {
    // @ts-ignore
    const dragRef = this.cdkDrag._dragRef;
    // @ts-ignore
    const initialContainer = dragRef._initialContainer;
    // @ts-ignore
    dragRef.exited.next({item: dragRef, container: dragRef._dropContainer});
    // @ts-ignore
    dragRef._dropContainer.exit(dragRef);
    // @ts-ignore
    dragRef.entered.next({item: dragRef, container: initialContainer});
    // @ts-ignore
    dragRef._dropContainer = initialContainer;
    // @ts-ignore
    dragRef._dropContainer.enter(dragRef, 0, 0);
  }
muellerdberlin commented 4 years ago

Thank you! Here my code which also works perfectly as long as you use the drop event only on a DropList.

move(event: CdkDragDrop<Element>, listToMoveIn) {

        // check if pointer was over another list, otherwise cancel
        if (event.isPointerOverContainer) {
             // move the element to another list
        }

}
agrt56 commented 3 years ago

The attribute isPointerOverContainer: true|false of the (cdkDropListDropped)=dropped($event) event is useful to evaluate wether the item should be allowed to drop or not, but there is no possibility to influence the placeholder, which is still at an unwanted position. A strict mode like shown in the draggula example or requested by @doyeonOh, which resets the placeholder position when the dragged item is leaving a droplist, would be very helpful.

A possible solution could be an event that triggers on exiting an droplist while not entering another... cdkDropListExited is no help there, while cdkDragMoved doesnt include informations wether the dragged item is currently over a droplist or not.

angular-robot[bot] commented 2 years ago

Just a heads up that we kicked off a community voting process for your feature request. There are 20 days until the voting process ends.

Find more details about Angular's feature request process in our documentation.

angular-robot[bot] commented 2 years ago

Thank you for submitting your feature request! Looks like during the polling process it didn't collect a sufficient number of votes to move to the next stage.

We want to keep Angular rich and ergonomic and at the same time be mindful about its scope and learning journey. If you think your request could live outside Angular's scope, we'd encourage you to collaborate with the community on publishing it as an open source package.

You can find more details about the feature request process in our documentation.

Buk1m commented 1 year ago

So here is my super hacky workaround. It would be nice to have an built in solution as it is extremely confusing with current placeholder behaviour.

I didn't test it too much as this is temp solution. I'm using @angular/cdk 9 in this project so be warned:

    private lastEntered: CdkDropList
    itemEntered($event: CdkDragEnter){
        this.lastEntered = $event.container
    }

    itemMoved(event: CdkDragMove<Item>): void {
        if(this.lastEntered !== event.source.dropContainer && !document.elementsFromPoint(event.pointerPosition.x, event.pointerPosition.y).some(el => el.classList.contains('cdk-drop-list'))){
            this.lastEntered.exit(event.source)
            event.source.dropContainer.enter(event.source, event.pointerPosition.x, event.pointerPosition.y)
            this.lastEntered = event.source.dropContainer
        }
    }

    itemDropped(event: CdkDragDrop<Item>, newStatus): void {
        this.lastEntered = null

        if(!event.isPointerOverContainer || event.container === event.previousContainer) {
            event.item.reset()
            return
        }
    }
    <div
            class="sortable-list"
            cdkDropList
            (cdkDropListDropped)="itemDropped($event, 'pending')"
            [cdkDropListEnterPredicate]="itemStatusNot('pending')"
        >
            <div
                *ngFor="let item of pendingItems"
                class="sortable-box"
                cdkDrag
                (cdkDragMoved)="itemMoved($event)"
                (cdkDragEntered)="itemEntered($event)"
                [cdkDragData]="item"
            >
            <div>
                Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged.

            </div>
            </div>
        </div>

dnd