【问题标题】:Drag and drop cdk Angular material拖放cdk Angular材质
【发布时间】:2020-05-04 00:52:02
【问题描述】:

我创建了 1 个带有图像的容器(使用 ngb-carousel)和 3 个放置这些图像的放置区,但是当我尝试在它们之间传输项目时遇到了一些问题。首先,每当我尝试将项目从我的图像容器移动到任何放置区域时,我总是得到相同的索引。

这是我的模板

<mat-card class="card">
    <div
        cdkDropList
        #todoList="cdkDropList"
        [cdkDropListData]="images"
        [cdkDropListConnectedTo]="[doneList, intermedio, menos]"
        cdkDropListOrientation="horizontal"
        class="contenedor">
        <ngb-carousel *ngIf="images">
            <ng-template *ngFor="let img of images" ngbSlide>
                <div class="picsum-img-wrapper" [cdkDragData]="img" cdkDrag>
                    <img [src]="path+img.imagen" width="100%" alt="Random first slide">
                </div>
            </ng-template>
        </ngb-carousel>
    </div>

    <div class="results">
        <div class="talents">
            <div class="example-container">
                <h4>(+) Talento más desarrollado</h4>
                <div cdkDropList #doneList="cdkDropList" [cdkDropListData]="list2"
                     [cdkDropListConnectedTo]="[intermedio, menos]"
                     class="example-list" (cdkDropListDropped)="drop($event)">
                    <ol class="example-box">
                        <li *ngFor="let l2 of list2" [cdkDragData]="l2" cdkDrag>
                            {{l2.nombre}}
                        </li>
                    </ol>
                </div>
            </div>
        </div>
        <div class="talents">
            <div class="example-container">
                <h4>Talento Intermedio</h4>
                <div cdkDropList #intermedio="cdkDropList" [cdkDropListData]="list3"
                     [cdkDropListConnectedTo]="[doneList, menos]"
                     class="example-list" (cdkDropListDropped)="drop($event)">
                    <ol class="example-box">
                        <li *ngFor="let l3 of list3" [cdkDragData]="l3" cdkDrag>
                            {{l3.nombre}}
                        </li>
                    </ol>
                </div>
            </div>
        </div>
        <div class="talents">
            <div class="example-container">
                <h4>(-) Talento menos desarrollado</h4>
                <div cdkDropList #menos="cdkDropList" [cdkDropListData]="list4"
                     [cdkDropListConnectedTo]="[intermedio, doneList]"
                     class="example-list" (cdkDropListDropped)="drop($event)">
                    <ol class="example-box">
                        <li *ngFor="let l4 of list4" [cdkDragData]="l4" cdkDrag>
                            {{l4.nombre}}
                        </li>
                    </ol>
                </div>
            </div>
        </div>
    </div>
</mat-card> 

这是我的拖放功能

drop(event: CdkDragDrop<any>) {
        if (event.previousContainer === event.container) {
            moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
        } else {
            /*transferArrayItem(event.previousContainer.data,
                event.container.data,
                event.previousIndex,
                event.currentIndex);*/

            const newArray = event.previousContainer.data.filter(e => e.id !== event.item.data.id);
            event.previousContainer.data = newArray;
            event.container.data.push(event.item.data)
        }
    }

我尝试使用 transferArrayItem,但它没有工作,因为我得到了错误的索引,所以我尝试更改 event.previousContainer.data 和 event.container.data,我使用 event.container.data 但它没有更改 event.previousContainer。数据。

任何想法为什么它不起作用? 提前致谢

【问题讨论】:

  • 这个问题很复杂,如果不尝试就很难回答,所以提供一个 stackblitz 可能会激励更多的人加入。我有两个非常初始/通用的建议:1)创建单独的 @987654323 @ 用于不同放置目标的函数,这可能会消除选择正确目标列表时出现的错误 2) 检查您是否将数组内的索引与全局 ID 混合在一起。
  • 您希望该图像始终保留在第一个容器中吗?

标签: javascript angular angular-material drag-and-drop


【解决方案1】:

您的代码几乎一切正常。

问题在于,由于所有带有cdkDropList 指令的&lt;div&gt; 容器都没有子容器,因此它们的高度为零,因此没有可以丢弃元素的区域。

一种可能的解决方案是将 cdkDropList 移动到更高的位置,例如 &lt;div class="example-container"&gt;,或者如果您不希望标题(如 (+) Talento más desarrollado&lt;/h4&gt;)触发拖动事件,那么您需要在下方提供一些高度,以便项目可以被拖到那里。

 <div class="results">
    <div class="talents">
        <div class="example-container" cdkDropList
             #doneList="cdkDropList" 
             [cdkDropListData]="list2"
             [cdkDropListConnectedTo]="[intermedio, menos]"
             class="example-list" 
             (cdkDropListDropped)="drop($event)"
                >
            <h4>(+) Talento más desarrollado</h4>
    <!-- Probably no need for this div then !-->
            <div> 
                <ol class="example-box">
                    <li *ngFor="let item of list2" [cdkDragData]="item" cdkDrag>
                        {{item.name}}
                    </li>
                </ol>
            </div>
        </div>
    </div>

Moving directive up in DOM tree stackblitz example.

使用这种方法,CdkDragDrop 事件的 previousIndex 始终等于“图像”数组的长度。我认为可能需要使用CdkDropListGroup,但将&lt;ngb-carousel&gt; 与DragDropModule 结合起来似乎是一个问题。如果一起使用,则 DragDropModule 无法正确识别拖动项的索引。

如我所料,如果图像只是简单列出,那么索引是正确的:
Without ngb-carousel - stackblitz example.

您的示例中的另一个问题是可拖动项目应该是具有角度 cdkDropList 指令的 HTML 元素的直接子元素。否则在拖动第二个元素时会出现以下错误:

错误:无法在“节点”上执行“插入前”:之前的节点 要插入的新节点不是该节点的子节点。

说了这么多,现在让我们尝试使用这些知识并将这段代码重构为一个工作示例。

首先是我们的模板:

 <div class="talents">
    <div class="example-container" >
       <h4>(+) Talento más desarrollado</h4>
          <ol class="example-box"  cdkDropList 
              #doneList="cdkDropList" 
              [cdkDropListData]="list2"
              [cdkDropListConnectedTo]="[intermedio, menos]"
              (cdkDropListDropped)="drop($event)">
                <li *ngFor="let item of list2" [cdkDragData]="item" cdkDrag>
                   {{item.name}}
                </li>
             </ol>
       </div>
   </div>

现在一些 CSS:

.example-box:empty {
  height:50px;
  border: 5px dashed #cecece;
}
.example-box:empty:hover:after {
  content: 'Drag & Drop items here';
  color: #aeaeae;
  font-weight: bold;
  font-size: 18px;
  width:50%;
  position: relative;
  left:25%;
  top:5px;
}

通过在没有子元素的元素上设置高度,我们创建了一个拖放区。添加边框和文本是一个很好的用户体验设计,它让我们的最终用户知道,项目可以被拖到给定的区域。

最后但并非最不重要的 TypeScript:

drop(event: CdkDragDrop<any>) {
// indexes are wrong due to ngb-carousel 
   if (event.previousContainer === event.container) {
// this is okay, no moving around in ngb-carousel, since it always displays one element;
        moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
   } else {
       let previousIndex = event.previousIndex;
       const element = event.previousContainer.element.nativeElement;
       const id = element.getAttribute('id');
       // Only indexes of items  dragged from carousel needs to be fixed
       if (id === this.carouselContainerId) {
           previousIndex = event.previousContainer.data.indexOf(event.item.data);
       } 
       transferArrayItem(event.previousContainer.data,
          event.container.data,
          previousIndex,
          event.currentIndex);  
   }

}

Working example - stackblitz

【讨论】:

    猜你喜欢
    • 2021-07-24
    • 2019-05-09
    • 2020-06-04
    • 2021-02-15
    • 2021-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多