Skip to content

Drag and Drop: After dropping a container to another cdkDropList inside of a cdkDropListGroup previousContainer is not updated #20541

Open
@joerg-bergner

Description

@joerg-bergner

What are you trying to do?

I try to move a dynamically inserted component from one cdkDropList to another inside of a cdkDropListGroup.

Here an excerpt of the HTML:

<div class="container-fluid mt-3">
    <div class="row" cdkDropListGroup>
        <div class="col-4 border min-vh-100" #dropList0Ref
             cdkDropList
             [cdkDropListData]="columns[0]"
             (cdkDropListDropped)="onDrop($event)">
            <ng-container #componentContainer0></ng-container>
        </div>
        <div class="col-4 border min-vh-100" #dropList1Ref
             cdkDropList
             [cdkDropListData]="columns[1]"
             (cdkDropListDropped)="onDrop($event)">
            <ng-container #componentContainer1></ng-container>
        </div>
        <div class="col-4 border min-vh-100" #dropList2Ref
             cdkDropList
             [cdkDropListConnectedTo]="['dropList0Ref', 'dropList1Ref']"
             [cdkDropListData]="columns[2]"
             (cdkDropListDropped)="onDrop($event)">
            <ng-container #componentContainer2></ng-container>
        </div>
    </div>
</div>

excerpt of component.ts

    ...
    columns: any[] = [ [], [], [] ];
    components0: ComponentRef<any>[] = [];
    components1: ComponentRef<any>[] = [];
    components2: ComponentRef<any>[] = [];
    
    @ViewChild('componentContainer0', { static: true, read: ViewContainerRef })
    componentContainer0: ViewContainerRef;

    @ViewChild('componentContainer1', { static: true, read: ViewContainerRef })
    componentContainer1: ViewContainerRef;

    @ViewChild('componentContainer2', { static: true, read: ViewContainerRef })
    componentContainer2: ViewContainerRef;

    
    ngAfterViewInit () {
        this.add(LogBookComponent, 0);
        this.add(CustomerListComponent, 0);
    }
    
    add (component, columnIndex: number) {
        let componentFactory;
        let cmp: ComponentRef<any>;
        let id;

        switch (columnIndex) {
            case 0:
                componentFactory = this.resolver.resolveComponentFactory(component);
                cmp = this.componentContainer0.createComponent(componentFactory);

                this.components0.push(cmp);
                id = cmp.componentType.name;
                this.columns[ 0 ].push({ id, title: `Gadget ${ id }` });
                cmp.changeDetectorRef.detectChanges();
                break;
            case 1:
                componentFactory = this.resolver.resolveComponentFactory(component);
                cmp = this.componentContainer1.createComponent(componentFactory);
                id = cmp.componentType.name;

                this.components1.push(cmp);
                this.columns[ 1 ].push({ id, title: `Gadget ${ id }` });
                cmp.changeDetectorRef.detectChanges();
                break;
            case 2:
                componentFactory = this.resolver.resolveComponentFactory(component);
                cmp = this.componentContainer2.createComponent(componentFactory);
                id = cmp.componentType.name;

                this.components2.push(cmp);
                this.columns[ 2 ].push({ id, title: `Gadget ${ id }` });
                cmp.changeDetectorRef.detectChanges();
                break;

            default:
                throw new Error('only three columns are supported');
        }
    }

    onDrop (event: CdkDragDrop<{}[]>) {
        console.log(``);
        console.log(``);
        console.log(``);
        console.log('event', event);
        console.log('this.columns', this.columns);

        const previousContainerId = this.getIdOf(event.previousContainer.id);
        const currentContainerId = this.getIdOf(event.container.id);

        console.log('previousContainerId', previousContainerId);
        console.log('currentContainerId', currentContainerId);

        if (event.previousContainer == event.container) {
            console.log(`moving inside ${ event.previousIndex } -> ${ event.currentIndex }`);

            switch (currentContainerId) {
                case 0:
                    this.componentContainer0.move(this.components0[ event.previousIndex ].hostView, event.currentIndex);
                    moveItemInArray(this.components0, event.previousIndex, event.currentIndex);
                    break;
                case 1:
                    this.componentContainer1.move(this.components1[ event.previousIndex ].hostView, event.currentIndex);
                    moveItemInArray(this.components1, event.previousIndex, event.currentIndex);
                    break;
                case 2:
                    this.componentContainer2.move(this.components2[ event.previousIndex ].hostView, event.currentIndex);
                    moveItemInArray(this.components2, event.previousIndex, event.currentIndex);
                    break;
            }
        }
        else {
            console.log(`transferring ${ previousContainerId } -> ${ currentContainerId } (${ event.previousIndex } -> ${ event.currentIndex })`);
            let previousComponents;
            let currentComponents;

            transferArrayItem(previousComponents, currentComponents, event.previousIndex, event.currentIndex);
            transferArrayItem(this.columns[ previousContainerId ], this.columns[ currentContainerId ], event.previousIndex, event.currentIndex);

            switch (currentContainerId) {
                case 0:
                    currentComponents = this.components0;
                    switch (previousContainerId) {
                        case 0:
                            // not possible is an move in array
                            console.log(`not possible is an move in array`);
                            break;
                        case 1:
                            previousComponents = this.components1;
                            this.componentContainer0.move(this.components1[ event.previousIndex ].hostView, event.currentIndex);
                            break;
                        case 2:
                            previousComponents = this.components2;
                            this.componentContainer0.move(this.components2[ event.previousIndex ].hostView, event.currentIndex);
                            break;
                    }
                    break;
                case 1:
                    currentComponents = this.components1;
                    switch (previousContainerId) {
                        case 0:
                            previousComponents = this.components0;
                            this.componentContainer1.move(this.components0[ event.previousIndex ].hostView, event.currentIndex);
                            break;
                        case 1:
                            // not possible is an move in array
                            console.log(`not possible is an move in array`);
                            break;
                        case 2:
                            previousComponents = this.components2;
                            this.componentContainer1.move(this.components2[ event.previousIndex ].hostView, event.currentIndex);
                            break;
                    }
                    break;
                case 2:
                    currentComponents = this.components2;
                    switch (previousContainerId) {
                        case 0:
                            previousComponents = this.components0;
                            this.componentContainer2.move(this.components0[ event.previousIndex ].hostView, event.currentIndex);
                            break;
                        case 1:
                            previousComponents = this.components1;
                            this.componentContainer2.move(this.components1[ event.previousIndex ].hostView, event.currentIndex);
                            break;
                        case 2:
                            // not possible is an move in array
                            console.log(`not possible is an move in array`);
                            break;
                    }
                    break;
            }
        }
    }
...

Reproduction

I'm able to move both components inside one cdkDropList. I also can move from on to another cdkDropList. But if I try to move it back to first cdkDropList or move it inside the new cdkDropList, an error occurs. If I debug the $event the event.previousContainer.id is still 0. So something wasn't updated. But I don't know what.

I know there are way's to write it shorter but before starting refactoring I need a working drag and drop.

StackBlitz: https://stackblitz.com/edit/angular-ivy-iuwvmb?file=src%2Fapp%2Fapp.component.ts

Steps to reproduce in Stackblitz:

  1. Move Hello Component 1 to second column
  2. Try to move Hello Component 1 back to first column
  3. see debug information and error in console

Environment

  • Angular: 9.1.9
  • CDK/Material: 9.2.4
  • Browser(s): Chrome
  • Operating System (e.g. Windows, macOS, Ubuntu): macOS

Metadata

Metadata

Assignees

No one assigned

    Labels

    P4A relatively minor issue that is not relevant to core functionsarea: cdk/drag-dropneeds investigationA member of the team needs to do further investigation to determine the root cause

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions