4

使用 @angular/cdk/drag-drop 模块(Angular Material Drag and Drop)时...有没有办法限制放置容器以便只接受一个值而不是多个值?我正在尝试创建表单,用户可以将图像拖放到应该只有一个项目的字段中。我正在使用标准示例代码来实现 拖放 | Angular Material,但找不到可以限制放置项目数量的解决方案,其次找不到保持拖动列表相同的解决方案(拖动的项目将保留在拖动容器中),因此您复制而不是将项目移动到放置容器。是否有任何解决方案或可以帮助提供示例代码的人?

HTML:

    <div class="example-container">
  <h2>To do</h2>

  <div
    cdkDropList
    #todoList="cdkDropList"
    [cdkDropListData]="todo"
    [cdkDropListConnectedTo]="[doneList]"
    class="example-list"
    (cdkDropListDropped)="drop($event)">
    <div class="example-box" *ngFor="let item of todo" cdkDrag>{{item}}</div>
  </div>
</div>

<div class="example-container">
  <h2>Done</h2>

  <div
    cdkDropList
    #doneList="cdkDropList"
    [cdkDropListData]="done"
    [cdkDropListConnectedTo]="[todoList]"
    class="example-list"
    (cdkDropListDropped)="drop($event)">
    <div class="example-box" *ngFor="let item of done" cdkDrag>{{item}}</div>
  </div>
</div>

TS:

import {Component} from '@angular/core';
import {CdkDragDrop, moveItemInArray, transferArrayItem} from '@angular/cdk/drag-drop';

/**
 * @title Drag&Drop connected sorting
 */
@Component({
  selector: 'cdk-drag-drop-connected-sorting-example',
  templateUrl: 'cdk-drag-drop-connected-sorting-example.html',
  styleUrls: ['cdk-drag-drop-connected-sorting-example.css'],
})
export class CdkDragDropConnectedSortingExample {
  todo = [
    'Get to work',
    'Pick up groceries',
    'Go home',
    'Fall asleep'
  ];

  done = [
    'Get up',
    'Brush teeth',
    'Take a shower',
    'Check e-mail',
    'Walk dog'
  ];

  drop(event: CdkDragDrop<string[]>) {
    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);
    }
  }
}
4

4 回答 4

1

这是我的版本的工作演示,允许覆盖。

确保您的屏幕足够宽,您可以看到两列。


你应该使用cdkDropListEnterPredicate

如果您的目标“插槽”已被填满,只需从这里返回 false。

请注意,您的处理程序是从this不是您的组件的上下文中调用的。所以你需要在你的组件中使用这样的 lambda 函数。

destinationNotEmptyPredicate = () => 
{
   return this.destinationArray.length == 0;
};

确保目的地列表有一个高度,以便您可以在其中实际放置一些东西。

但是,如果您需要允许覆盖“假列表”中的现有单个项目(并且您可能会这样做),那么它会有点棘手。您不想使用此谓词(因为它会阻止您删除任何内容,除非您首先删除现有项目)。

所以在这种情况下,你需要做一个 CSS 调整来隐藏已经存在的项目(当你将鼠标悬停在它上面时)。

#even 是目标列表。

#even.cdk-drop-list-dragging .cdk-drag:not(.cdk-drag-placeholder) {
   display: none;
}

还设置[cdkDropListSortingDisabled]="false"为避免奇怪的动画故障。

当您“删除”该项目时,您的目标列表应仅包含一项:

drop(event: CdkDragDrop<number[]>) {
    if (event.previousContainer === event.container) {
      moveItemInArray(
        event.container.data,
        event.previousIndex,
        event.currentIndex
      );
    } else {
      this.even = [event.item.data];
    }
  }

请注意我如何仍然使用cdkDropListEnterPredicate这里来只允许删除偶数。

于 2021-06-27T20:19:27.157 回答
1

好的,这应该工作:

movementCount: number = 0;

drop(event: CdkDragDrop<string[]>) {
   if (event.previousContainer === event.container) {
      moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
    } else if(this.movementCount === 0){
       this.movementCount++;  // block next object from being moved
       // copy obj being moved
       var movingObj = event.previousContainer.data[event.previousIndex];

       transferArrayItem(event.previousContainer.data,
                    event.container.data,
                    event.previousIndex,
                    event.currentIndex);

       // transfer complete so copy object back
       event.previousContainer.data.push(movingObj);    
  }
}

我使用计数器来确定是否允许移动,但布尔值也可以(更好)。您只需要添加额外的代码,因此当图像从它所携带的 div 中删除/删除时,计数器将返回为零/假,因此可以在需要时拖动另一个图像。

希望有帮助。

于 2019-11-27T02:26:04.960 回答
0

不确定它是否仍然有用,但我使用2了一些方法来限制放置项目,1如果另一个项目被删除,则取消之前放置的项目:

  1. 禁用 HTML 中的排序

    cdkDropListSortingDisabled

  2. 将项目总数.ts限制为1,并删除索引处1的那个(已经在里面的那个),因为排序禁用将添加下一个索引处0

onDrop在您的方法中添加以下功能:

for (let  i=0 ; i<2 ; i++){
   this.items.splice( 1 ,1)
}
于 2021-07-10T07:54:07.297 回答
0

另一种解决方案是将 设置[cdkDropListData]="[]"为硬编码的空列表。所以从 cdk 的角度来看,这是一个列表,但对于您的应用程序而言并非如此。

然后,您只需在该位置显示您想要的任何内容(如果已设置该项目),并处理cdkDragDrop事件以更新它。

    <div class="slot"        
         cdkDropList
         [cdkDropListData]="[]"
         (cdkDropListDropped)="drop($event)">

       <!-- display your item here with *ngIf -->

    </div>


.slot
{
   min-height: 50px;
}
于 2021-06-27T21:14:56.523 回答