使用 primeng p-tree 组件停止节点删除事件

Stop node drop event with primeng p-tree component

我正在使用 primeng p-tree 组件,我想禁止将某些节点类型放入另一个节点类型中。

例如,我有文件夹类型的节点和文件类型的另一个节点,我只希望文件类型的节点移动到文件夹类型的节点内。我想禁止在另一个文件夹节点内移动文件夹节点。 (和其他规则

<p-tree [value]="filesTree7" draggableNodes="true" droppableNodes="true" dragdropScope="files" selectionMode="single" [(selection)]="selectedFile2" [contextMenu]="cm" (contextmenu)="onContextMenu($event)"
          (onNodeDrop)="onNodeDrop($event)"></p-tree> 

我试图像这样阻止液滴的传播:

onNodeDrop(event) {
    console.log("onNodeDrop");
    event.originalEvent.stopPropagation();
    event.originalEvent.preventDefault();
    return;
}

但它不起作用。

当我在这里查看 primeng 代码时:primeng tree component code source 似乎 onNodeDrop 事件发出得太晚了。

你有什么想法可以实现我所需要的吗?

如果您希望单个节点不可放置或拖动,您必须在数组中设置参数 draggable/droppable:

{
    "label": "Note e Commenti",
    "icon": "fa-file-word-o",
    "draggable":false,
    "droppable":false,
    "data": {
        "id": 1,
        "nome": "Note e Commenti",
        "testo": "Note e Commenti",
        "idCategoria": 2,
        "idTipologia": 1
    }
},

直到 Tree 组件的 this is implemented, the workaround could be to override the allowDrop method 并编写您自己的放置逻辑实现。 然而,您可能(实际上您应该)想要使用原始方法中涵盖的删除逻辑,只需添加您的位即可。

现在 prototyping 可能看起来像这样:

  • 在你使用pTree的组件中,通过ViewChild

    获取Tree
    @ViewChild(Tree) tree: Tree;
    
  • 然后在 constructorngOnInit 或任何适合您的情况下,prototype allowDrop

    Tree.prototype.allowDrop = (dragNode: any, dropNode: any, dragNodeScope: any): boolean => {
      return this._overrideAllowDrop(dragNode, dropNode, dragNodeScope)
    }
    

_overrideAllowDrop 用于简洁目的。要取消掉落只需 return false.

此外,您可以利用树实例的 dragDropService 来显示错误消息,以防删除失败。

例如:

this.tree.dragDropService.dragStop$.subscribe((data) => {
  if(this.failed){ // set failed to true in your custom drop logic
    alert('Error!')
  }
})

但此解决方法的缺点是丢弃逻辑应在 UI 端,如果您的逻辑需要后端干扰,则此解决方法可能没有太大帮助。

虽然后端涉及到我的案例,但逻辑很简单,所以我将它移到了 UI 一侧,因此 prototyping 达到了目的。

这有一些重要的附加细节,尤其是 bind() 函数

    export class myClass implements AfterViewInit {
      @ViewChild('primeTree') primeTree: Tree;  // named in HTML
    
      ngAfterViewInit() {
        // get the original function AND bind it to the tree - important!
        const originalAllowDrop = this.primeTree.allowDrop.bind(this.primeTree);
        
        // replace the allowDrop function with this
        this.primeTree.allowDrop = (dragNode: TreeNode, dropNode: TreeNode, dragNodeScope: any): boolean => {
          // let the original function do the pre-check, and then check for special cases
          return originalAllowDrop(dragNode, dropNode, dragNodeScope) && this.allowDrop(dragNode, dropNode, dragNodeScope);
        }

  }

  private allowDrop(dragNode: TreeNode, dropNode: TreeNode, dragNodeScope: any): boolean {
    // your logic here
    if (imNotHappy) {
      return false
    }
    return true;
  }
}