Search code examples
angulardrag-and-dropangular7angular-cdk

Angular 7 Drag and Drop - Dynamically Create Drop Zones


Is there a way to dynamically create drop zones? I'm having some troubles with ngFor and cdkDropList.

Here is my first list and draggable elements:

       <div class="subj-container" 
        cdkDropListOrientation="horizontal" 
        cdkDropList 
        #subjectList="cdkDropList"
        [cdkDropListData]="subjects"  
        [cdkDropListConnectedTo]="[lessonList]" 
        (cdkDropListDropped)="drop($event)"
        >
            <div class="subject" *ngFor="let subject of subjects" cdkDrag>
                {{subject.name}}
            </div>
        </div>

And here is my second list:

          <div class="conta" cdkDropList
                #lessonList="cdkDropList"
                [cdkDropListData]="appointment.lessons"
                [cdkDropListConnectedTo]="[subjectList]"
                (cdkDropListDropped)="drop($event)">
                    <div class="sub" cdkDrag *ngFor="let lesson of appointment.lessons">
                        {{lesson.name}}
                </div>
           </div>

Now, div with class 'conta' is inside of a *ngFor.

My problem is, I suppose, with my second list. If I drag an element from second list to list one, it works normally, but if I try to drag element from list one to any instance of list in second list, it can't recognize that the element is being dragged. Demo here:

problem demo

Am I doing something wrong here? The typescript part is working fine.

Thanks


Solution

  • After a full day of research, I found this pull request on Angular CDK repository on Github. Now, since I did not know how to integrate cdkDropListGroup into my example, I decited to create an array of IDs which will be added to [cdkDropListConnectedTo].

    Each instance of my second list will have generated ID, and that ID will be added to array with suitable prefix (in my second list, on cdkDropList):

    <div cdkDropList
          [attr.id]="addId(i, j)"
          [cdkDropListData]="appointment.lessons"
          [cdkDropListConnectedTo]="[subjectList]"
          (cdkDropListDropped)="drop($event)"
    >
    

    addId method:

    addId(i, j) {
        this.LIST_IDS.push('cdk-drop-list-' + i + '' + j);
        return i + '' + j;
    }
    

    (cdk-drop-list- is an ID prefix. CDK places this prefix on every element with cdkDropList attribute)

    So, my array will look like:

    • cdk-drop-list-00
    • cdk-drop-list-01
    • cdk-drop-list-02
    • etc.

    Now, I pass that array to [cdkDropListConnectedTo] in my first list:

    <div class="subj-container" 
        cdkDropListOrientation="horizontal"
        cdkDropList 
        #subjectList="cdkDropList"            
        [cdkDropListData]="subjects" 
        [cdkDropListConnectedTo]="LIST_IDS"
        (cdkDropListDropped)="drop($event)"
    >
    

    And it works flawlessly!

    Hope this will help anybody with the same problem. Also, take a look at the pull request I mentioned, my solution is only a workaround, there is probably a better solution with cdkDropListGroup