Can't cancel tool when ExternalObjectsDropped event catched

I have a diagram that can be build up by the user by dragging over elements from the palette. I wanted to prevent user from building invalid diagram - all elements should be linked (but drop should be allowed for first node as there must be initial point). I found on forum a code below, but it does not do what I really wanted here (note: notification code is my custom function):

diagram.addDiagramListener('ExternalObjectsDropped', function (_e: DiagramEvent) {
		const newnode = diagram.selection.first();
		if (
			newnode &&
			(newnode as Node).linksConnected.count === 0 &&
			diagram.model.nodeDataArray.length > 1
		) {
			diagram.commandHandler.deleteSelection();
			if (showNotificationBox) {
				showNotificationBox(
					DIAGRAM_NOTIFICATION.ERROR,
					i18next.t('policy.classification.custom.modal.dropNotAllowed')
				);
			}
		}
	});

diagram.commandHandler.deleteSelection(); removes the current existing node from the diagram and keeps a newly dragged node, but I wanted to remove the dragged node and keep the current diagram structure instead.

When I changed this function to diagram.currentTool.doCancel(); is does nothing, new node is dropped.

Is this possible to do using this event?

Before I tried using mouseDrop diagram function like this:

myDiagram.mouseDrop = function(e) {
    myDiagram.currentTool.doCancel();
  }

It worked correctly for dropping new nodes from the palette but prevented the user from moving the existing node around the diagram, each time I moved node to a different place it was moved back with notification.

So what I wanted to achieve is allow moving nodes around, allow to drop node on a node (I have a function that automatically links them), prevent from dropping on the diagram if not linked.

Yes, the Diagram.mouseDrop event handler is supposed to handle all cases of dropping parts onto the background of the diagram, but not when dropping onto parts.

The “ExternalObjectsDropped” DiagramEvent is only for cross-Diagram drops, for anywhere in the viewport, but not for intra-Diagram drag-and-drops.

You can decide whether the drag-and-drop was external or internal by checking the Diagram.currentTool:

        $(go.Diagram, "myDiagramDiv",
          { . . .,
            mouseDrop: function(e) {  // InputEvent
              console.log(e.diagram.currentTool instanceof go.DraggingTool);
            }
          })

If it is a DraggingTool, it’s an internal drag-and-drop.
If it is not, it’s an external drag-and-drop.

OR

If you do want to use the “ExternalObjectsDropped” DiagramEvent, it’s a bit more complicated because that happens later in the process, and there are two Diagrams and two DraggingTools involved. But this will work to cancel the cross-diagram drag-and-drop:

            "ExternalObjectsDropped": function(e) {
              e.diagram.toolManager.draggingTool.transactionResult = null;
            }

The complication is because it’s the other diagram’s dragging tool that is running (e.g. Palette.currentTool will be a DraggingTool) and the target diagram’s Diagram.currentTool is not a DraggingTool. BUT the target diagram’s DraggingTool is being called (i.e. the ToolManager.draggingTool), because we want all of the target diagram’s appearances for nodes (templates) and node behaviors and diagram behaviors to take effect during a drag-and-drop which might cross over many different diagram instances.

I looked at my code again today, and I found out I can mix both of my previous solutions to make it work as expected, here is the code:

diagram.mouseDrop = function (_e: InputEvent) {
		const newNode = diagram.selection.first();
		if (
			newNode &&
			(newNode as Node).linksConnected.count === 0 &&
			diagram.model.nodeDataArray.length > 1
		) {
			diagram.currentTool.doCancel();
			if (showNotificationBox) {
				showNotificationBox(
					DIAGRAM_NOTIFICATION.ERROR,
					i18next.t('policy.classification.custom.modal.dropNotAllowed')
				);
			}
		}
	};

I just needed to check if the node is not connected and run doCancel() and skip it otherwise.
Just leaving the solution here if anyone will have the same problem in the future.
Thanks for your help!

1 Like