CdkDragDrop 和 ngTemplateOutlet

5

我正在尝试使用Angular Material 7发布的拖放功能。

我使用ngTemplateOutlet将我的模板分成可重用的部分,每个选项都可以是一个Thing™或具有更多子Thing™的嵌套Thing™。

嵌套的Thing™显示为扩展面板。我希望所有一级Things™都可以像列表一样重新排序。

好吧,好吧,显然这是一个带有普通和嵌套选项的可重新排序侧边栏,假装它不是那么明显

这是我最初编写的代码。

<div cdkDropList (cdkDropListDropped)="dropItem($event)" lockAxis="y">
  <ng-container *ngFor="let thing of things">
      <ng-container
        *ngTemplateOutlet="!thing.children ? singleThing : multipleThing; context: { $implicit: thing }"
      ></ng-container>
    </ng-container>
</div>

<ng-template #singleThing let-thing>
  <div cdkDrag>
    <ng-container *ngTemplateOutlet="thingTemplate; context: { $implicit: thing }"></ng-container>
  </div>
</ng-template>

<ng-template #multipleOption let-thing>
  <mat-expansion-panel cdkDrag (cdkDropListDropped)="dropItem($event)">
    <mat-expansion-panel-header>
      <mat-panel-title>
        <p>Nested thing title</p>
        <span cdkDragHandle></span>
      </mat-panel-title>
    </mat-expansion-panel-header>

    <ng-container *ngFor="let childThing of thing.children">
      <div class="childThing">
        <ng-container *ngTemplateOutlet="thingTemplate; context: { $implicit: childThing }"></ng-container>
      </div>
    </ng-container>
  </mat-expansion-panel>
</ng-template>

<ng-template #thingTemplate let-thing>
  <p>I'm a thing!</p>
  <span cdkDragHandle></span>
</ng-template>

问题:单个Things™是可拖动的,但它们没有像cdkDropList一样被强制为列表,我可以在任何地方拖动它们。
我曾经遇到过类似的问题,当尝试使用模板插座并将ng-template放回“HTML流”中时,解决了该问题,因此我尝试了相同的方法。
<div cdkDropList (cdkDropListDropped)="dropItem($event)" lockAxis="y">
  <ng-container *ngFor="let thing of things">
      <ng-container
        *ngIf="!thing.children; then singleThing; else multipleThing"
      ></ng-container>
        <ng-template #singleThing>
          <div cdkDrag>
            <ng-container *ngTemplateOutlet="thingTemplate; context: { $implicit: thing }"></ng-container>
          </div>
        </ng-template>

        <ng-template #multipleOption>
          <mat-expansion-panel cdkDrag (cdkDropListDropped)="dropItem($event)">
            <mat-expansion-panel-header>
              <mat-panel-title>
                <p>Nested thing title</p>
                <span cdkDragHandle></span>
              </mat-panel-title>
            </mat-expansion-panel-header>

            <ng-container *ngFor="let childThing of thing.children">
              <div class="childThing">
                <ng-container *ngTemplateOutlet="thingTemplate; context: { $implicit: childThing }"></ng-container>
              </div>
            </ng-container>
          </mat-expansion-panel>
        </ng-template>
    </ng-container>
</div>

<ng-template #thingTemplate let-thing>
  <p>I'm a thing!</p>
  <span cdkDragHandle></span>
</ng-template>

当然可以,它起作用了!

变化不大,我们使用了ngIf替换了第一个ngTemplateOutlet,并删除了Thing™的内容绑定,因为现在两个模板都有其本地变量引用,感谢共享作用域。

为什么第二种方式能够起作用而第一种不能呢?

额外加分:是否可能保持第一种代码结构使其工作,因为对我来说,这种方式显然更易读和干净?


你有找到任何解决方法吗?遇到了同样的问题吗? - Ganesh Jangam
1个回答

7

我遇到了同样的问题,甚至在GitHub上报告了这个问题

原来这是由于cdkDropListcdkDrag的分离性导致的。 cdkDrag必须位于带有cdkDropList的标记内部嵌套的标签中,否则拖动的元素将无法检测到放置区域。

在您的情况下,解决方案是在cdkDropList下面添加一个额外的<div cdkDrag>,并且只在该标签下调用具有ngTemplateOutlet的模板。


1
我怀疑,不幸的是我必须将cdkDrag分开放置在两个不同的元素上,所以我会选择不太干净的选项。但感谢您的解释和链接,我将把这个标记为最佳答案。 - Paolo 'Callo' Caleffi

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