cdkDragHandle doesn't work inside child component
Asked Answered
R

5

22

Using @angular/cdk 7.2.1: If defining a parent component holding a cdkDropList and a nested list of cdkDrag components, defining a cdkDragHandle inside the nested child component doesn't work. If the same structure is all in the same component, cdkDragHandle works perfectly.

https://stackblitz.com/edit/angular-wfvmuj?embed=1&file=src/app/hello.component.html

Has anyone found a fix to get cdkDragHandle to work even when not defined in the same component as cdkDrag?

Ruisdael answered 19/2, 2019 at 19:12 Comment(1)
Found the issue: github.com/angular/material2/issues/13784Ruisdael
G
34

This solution worked for me:

Parent Component:

<div cdkDropList #list="cdkDropList"
  [cdkDropListData]="myArray"
  (cdkDropListDropped)="drop($event)">

  <app-item
    *ngFor="let item of myArray"
    cdkDrag>
    <div cdkDragHandle></div>
  </app-item>

</div>

Child Component (app-item):

<div class="drag-container">
  <ng-content></ng-content>
  <div class="drag-handle">drag here</div>
</div>

Then style the cdk-drag-handle class in the parent component. cdk-drag-handle comes with material, so we do not need to apply it manually:

.cdk-drag-handle {
   width: 100%;
   height: 100%;
   position: absolute;
   z-index: 100;
   background-color: transparent;
   cursor: move;
 }

Then style the drag-container with position: relative and whatever you want. I have an item inside it (drag-handle) which also takes the full width and height of the container, that contains an image (just as a sidenote).

Guimpe answered 24/7, 2019 at 12:18 Comment(2)
Thank you, lajuma, for the proposed solution. This is basically what is suggested by others in the referenced issue link above, github.com/angular/material2/issues/13784.Ruisdael
Great solution! You just introduced me to <ng-content> tag. ThanksIncrease
C
9

This worked for me: Instead of using cdkDragHandle, just stop mouse down event propagation as bellow. Then only header can be dragged.

<div>
  <header></header>
  <body (mousedown)="$event.stopPropagation()"></body>
</div>
Chrisoula answered 9/1, 2020 at 21:16 Comment(0)
H
4

Not sure when this was added , setting cdkDragRootElement in the child worked for me.

In the child component <div cdkDrag cdkDragRootElement="app-bot-prompt-selector"> app-bot-prompt-selector is the parent element that needs to be drag able

https://material.angular.io/cdk/drag-drop/api#CdkDrag

Harrington answered 7/11, 2020 at 6:35 Comment(0)
C
0

Because CdkDrag use @ContentChildren to catch all CdkDragHandles, so you have to define all CdkDragHandles as content children BUT there is another solution if you don't want to define cdkDragHandle as descendants content children, you can add cdkDragHandle to cdkDrag manually:

@Component({
  selector: "child-component",
  template: `
    <div cdkDragHandle>handle</div>
  `
)}
export class ChildComponent {

  @ViewChild(CdkDragHandle, { static: true }) handle: CdkDragHandle;

  constructor(@Optional() @Inject(CDK_DRAG_PARENT) public cdk) {}

  ngAfterViewInit() {
    this.cdk._handles.length = 1;
    this.cdk._handles._results = [this.handle];
    this.cdk._handles.changes.next();
  }
}
Comatose answered 10/1, 2023 at 19:23 Comment(0)
B
0

A solution I found to this problem is to add the drag handle as a content but not the main one, because I needed that for other components.

  
<div cdkDropListGroup>
<div 
#mainContainerList="cdkDropList" 
cdkDropList 
(cdkDropListDropped)="drop($event)"  
[cdkDropListData]="this.dataModel.model.items"

class="page-builder-content">
    <div cdkDrag *ngFor="let component of  this.dataModel.model.items;let i=index">
           
        
       <app-component-selector >
<--- Here -->
       <span dragHandle cdkDragHandle class="material-icons">
        open_with
        </span>
<--- Here -->
<div >
other data for view
</div>
</app-component-selector>

then in the sub child component I use this dragHandle where I need it

   <div class="col-2">
        <ng-content select="[dragHandle]">

        </ng-content>
       </div>
<ng-content></ng-content><-- Other data-->
Braeunig answered 19/1, 2023 at 18:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.