Angular 7 拖放 - 动态创建放置区

36

有没有办法动态创建拖放区域?我的ngFor和cdkDropList出了些问题。

以下是我的第一个列表和可拖动元素:

       <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>

这是我的第二个列表:

          <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>

现在,带有'class'为“conta”的

标签在*ngFor的内部。

我的问题是,我想,出现在第二个列表中的元素可能会出问题。如果我将元素从第二个列表拖到列表一中,则正常工作,但是如果我尝试将元素从列表一拖到第二个列表中的任何实例中,则无法识别正在拖动的元素。演示在这里:

问题演示

我做错了什么吗? TypeScript部分工作正常。

谢谢


如果您删除使其多行的样式,您的第二个列表是否有效?下拉列表只能是水平或垂直的。您似乎在这里有一个网格,这是行不通的,因为存在依赖于知道在x或y维度中计算下拉列表元素的相对距离的内在逻辑。 - Lightheaded
@Lightheaded - 是的,我确实想到了这一点,并删除了所有样式,但是没有效果。 我找到了一个解决方案。 cdkDropListConnectedTo 存在问题,它连接到了 null,所以我做了我的解决方法。请查看下面的答案,谢谢! - sebamed
你有这个的可行示例吗? - Muhammad Daniyal
6个回答

38

经过一整天的研究,我在 Github 上找到了 Angular CDK 存储库中的拉取请求。由于我不知道如何将 cdkDropListGroup 集成到我的示例中,因此我决定创建一个 ID 数组,该数组将被添加到 [cdkDropListConnectedTo] 中。

我的第二个列表的每个实例将生成一个 ID,并将该 ID 添加到带有适当前缀的数组中(在我的第二个列表上,对于 cdkDropList):

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

addId 方法:

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

(cdk-drop-list-是一个ID前缀。CDK将该前缀放在每个具有cdkDropList属性的元素上)

所以,我的数组将会长成这样:

  • cdk-drop-list-00
  • cdk-drop-list-01
  • cdk-drop-list-02
  • 等等。

现在,我将该数组传递给我的第一个列表中的[cdkDropListConnectedTo]

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

而且它运行得非常完美!

希望这能对有同样问题的人有所帮助。同时,请查看我提到的拉取请求,我的解决方案只是一个解决方法,可能存在更好的解决方法,例如使用cdkDropListGroup


1
cdkDropListGroup目前还没有发布。请关注下一个版本的发布。同时,我一直在使用相同的方法 - 使用列表ID进行映射。目前似乎没有更好的方法来做到这一点。每当您提到的功能发布时,您可以删除所有混乱的ID :) - Lightheaded
1
cdkDropListGroup已经发布。我能在哪里获取带有cdkDropListGroup的演示? - Jomy Joseph
1
我在StackBlitz上添加了一个使用cdkDropListGroup的演示,网址为https://stackblitz.com/edit/angular-a4ftm7 - Maxxx
我也在尝试实现同样的事情。有人能帮我吗?请查看链接:https://stackoverflow.com/questions/59386696/how-to-get-mat-tree-node-element-from-drop-event-in-the-mat-tree-in-angular2 - Rahul Rai
这种方法对于可以适应对话框的行非常有效。然而,当有太多无法适应可见区域的行时,拖放无法确定当前索引。如果我选择最后一行,并尝试通过垂直滚动条将其移动到顶部,它会失败。有什么想法来解决这个问题吗? - user3097695

20

来源 链接

演示 链接

对于动态拖放列表,我们可以使用ID代替#模板变量。

enter image description here

app.component.html

<div class="col-md-3" *ngFor="let week of weeks">
  <div class="drag-container">
    <div class="section-heading">Week {{week.id}}</div>

    <div cdkDropList id="{{week.id}}" [cdkDropListData]="week.weeklist"
      [cdkDropListConnectedTo]="connectedTo" class="item-list" (cdkDropListDropped)="drop($event)">
      <div class="item-box" *ngFor="let weekItem of week.weeklist" cdkDrag>Week {{week.id}} {{weekItem}}</div>
    </div>
  </div>
</div>

app.component.ts

->

app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  weeks = [];
  connectedTo = [];


  constructor() {
    this.weeks = [
      {
        id: 'week-1',
        weeklist: [
          "item 1",
          "item 2",
          "item 3",
          "item 4",
          "item 5"
        ]
      }, {
        id: 'week-2',
        weeklist: [
          "item 1",
          "item 2",
          "item 3",
          "item 4",
          "item 5"
        ]
      }, {
        id: 'week-3',
        weeklist: [
          "item 1",
          "item 2",
          "item 3",
          "item 4",
          "item 5"
        ]
      }, {
        id: 'week-4',
        weeklist: [
          "item 1",
          "item 2",
          "item 3",
          "item 4",
          "item 5"
        ]
      },
    ];
    for (let week of this.weeks) {
      this.connectedTo.push(week.id);
    };
  }

  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);
    }
  }
}

18

使用cdkDropListGroup,您现在可以执行以下操作:

<div cdkDropListGroup>

  <div cdkDropList
    [cdkDropListData]="data"
    (cdkDropListDropped)="drop($event)">
    <div class="row m-2">
        <div *ngFor="let i of data" cdkDrag>{{i}}</div>          
    </div>
  </div>

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

</div>

这种情况下不再需要使用cdkDropListConnectedTo。 请参见https://github.com/angular/material2/blob/master/src/cdk/drag-drop/drag-drop.md


5

我也面临了这个问题。我尝试了id方法,但在使用时并不太自信。当我在addId()函数中进行console.log时,我可以看到相同的id多次重复。

因此,我尝试使用@ViewChildren装饰器,实时获取cdkList组件,这对我非常有效。

在TypeScript中

  cdkDropTrackLists: CdkDropList[];
  @ViewChildren(CdkDropList)
  set cdkDropLists(value: QueryList<CdkDropList>) {
    this.cdkDropTrackLists = value.toArray();
  }

在模板中

<div
        cdkDropList
        class="track-list"
        cdkDropListSortingDisabled
        [cdkDropListData]="paragraphIdentifiers"
        (cdkDropListDropped)="drop($event)"
        [cdkDropListConnectedTo]="cdkDropTrackLists">
</div>

我认为当 cdkDropLists 作为一个 QueryList 时,它具有一个可观察的属性 changes,我可以通过改进它来提高效率。


2
我使用动态组列表和cdkDropListGroup构建了一个 stackblitz示例。我会在列表中的项目上记住第一个列表的名称。通过记住第一个列表,我可以跟踪哪些对象发生了变化,这对于构建某些情况非常有用。它还使我有可能更改已移动的项目的背景颜色,清楚地显示出了变化内容。请注意,保留HTML标签。

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接