ng2-dragula添加新项目后,它会显示在顶部

问题描述

我正在使用ng2-dragula进行拖放功能。我在将第一个元素(或任何元素)拖放到末尾,然后尝试使用addNewItem按钮将新项目添加到数组时看到问题,新项目没有被添加到末尾。如果我不将元素放到末尾,则会在UI的末尾添加新项。 在任何情况下,我都希望新项目显示底部。任何帮助表示赞赏。 Angular 7无法重现此问题。我看到Angular 9会发生这种情况。

JS

export class SampleComponent {

  items = ['Candlestick','Dagger','Revolver','Rope','Pipe','Wrench'];
  constructor(private dragulaService: DragulaService) { 
    dragulaService.createGroup("bag-items",{
      removeOnSpill: false
    });
  }

  public addNewItem() {
    this.items.push('New Item');
  }
}

HTML

<div class="container" [dragula]='"bag-items"' [(dragulaModel)]='items'>
    <div *ngFor="let item of items">{{ item }}</div> 
</div>

enter image description here

我编辑了注释中的stackblitz,以帮助可视化问题。将单位拖到列表底部时,似乎会触发此事件。更新的stackblitz:https://stackblitz.com/edit/ng2-dragula-base-ykm8fz?file=src/app/app.component.html ItemsAddedOutOfOrder

解决方法

您可以尝试恢复掉落的旧物品的位置。

constructor(private dragulaService: DragulaService) {
  this.subscription = this.dragulaService.drop().subscribe(({ name }) => {
    this.dragulaService.find(name).drake.cancel(true);
  });
} 

Forked Stackblitz

说明

Ivy和ViewEngine在特定索引处插入ViewRef的方式有所不同。他们在不同的beforeNode上中继

如果我们将项目添加到末尾,Ivy总是返回ViewContainer主机(注释节点)ref

export function getBeforeNodeForView(viewIndexInContainer: number,lContainer: LContainer): RNode|
    null {
  const nextViewIndex = CONTAINER_HEADER_OFFSET + viewIndexInContainer + 1;
  if (nextViewIndex < lContainer.length) {
    const lView = lContainer[nextViewIndex] as LView;
    const firstTNodeOfView = lView[TVIEW].firstChild;
    if (firstTNodeOfView !== null) {
      return getFirstNativeNode(lView,firstTNodeOfView);
    }
  }

  return lContainer[NATIVE]; <============================= this one
}

ViewEngine返回最后渲染的节点(最后一个<li/>元素)ref

function renderAttachEmbeddedView(
    elementData: ElementData,prevView: ViewData|null,view: ViewData) {
  const prevRenderNode =
      prevView ? renderNode(prevView,prevView.def.lastRenderRootNode!) : elementData.renderElement;
  ...
}

解决方案可能是将拖动的元素还原回原始容器,以便我们可以让内置ngForOf Angular指令进行智能区分。

顺便说一句,在Angular材质DragDropModule中使用了相同的技术。它会记住拖动元素的位置,并在拖放项目后将其插入到DOM中重要的旧位置。