{"_id":"598622fbd09433000f1b97f7","category":{"_id":"598622f9d09433000f1b97e0","version":"598622f9d09433000f1b97dd","project":"5707c6875309d117006948d4","__v":0,"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2016-04-08T14:56:07.661Z","from_sync":false,"order":2,"slug":"documentation","title":"Guides"},"parentDoc":null,"user":"54d742a80771980d0052f4b5","project":"5707c6875309d117006948d4","version":{"_id":"598622f9d09433000f1b97dd","project":"5707c6875309d117006948d4","__v":1,"createdAt":"2017-08-05T19:56:41.267Z","releaseDate":"2017-08-05T19:56:41.267Z","categories":["598622f9d09433000f1b97de","598622f9d09433000f1b97df","598622f9d09433000f1b97e0","598622f9d09433000f1b97e1"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"4.1.0","version":"4.1.0"},"__v":0,"updates":["58877ea023d3cc3100e73ebd","58877ea18c43372500b05474","58877ef8e5ef250f00cb9049","5888628be7c13a2d00751e73","58a5a520d498872f0022e400"],"next":{"pages":[],"description":""},"createdAt":"2016-10-04T10:39:38.807Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":14,"body":"[Options](#options)\n[Event](#event)\n[Override default behaviour](#override-default-behaviour)\n[Drag a node outside of the tree](#drag-a-node-outside-of-the-tree)\n[Drag an external element into the tree](#drag-an-external-element-into-the-tree)\n[Drag to an empty tree](#drag-to-an-empty-tree)\n[Styling](styling)\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Options\"\n}\n[/block]\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"options = {\\n  allowDrag: (node) => node.isLeaf,\\n  allowDrop: (element, { parent, index }) {\\n    // return true / false based on element, to.parent, to.index. e.g.\\n    return parent.hasChildren;\\n  },\\n  getNodeClone: (node) => ({\\n    ...node.data,\\n    id: uuid.v4(),\\n    name: `copy of ${node.data.name}`\\n  })\\n};\\n\\noptions2 = {\\n  allowDrag: true,\\n  allowDrop: false\\n};\\n\\n<tree-root\\n\\t\\t[nodes]=\\\"nodes\\\"\\n\\t\\t[options]=\\\"options\\\"></tree-root>\",\n      \"language\": \"javascript\",\n      \"name\": \"Allow drag & drop using `allowDrag` flag in tree options\"\n    }\n  ]\n}\n[/block]\nDragging:\nEnable dragging with `allowDrag` option (default false) accepts either a boolean or a function:\n* Boolean value - decides if drop is allowed or not on the tree\n* Function - decides on a per node basis if drop is allowed. The function receives:\n  * node - the dragged TreeNode\n\nDropping:\nEnable selective dropping with the `allowDrop` option (default true) accepts either a boolean or a function:\n* Boolean value - decides if drop is allowed or not on the tree\n* Function - decides on a per node basis if drop is allowed. The function receives:\n  * element - the dragged element\n  * to - drop location structure\n    * parent - the parent node\n    * index - the index inside the parent's children where the element is dropped\n\nCopying:\nThe default behaviour of the tree is to copy the node when `ctrl` is pressed while dropping the node\n* By default the tree will shallow-clone the node data and generates a random ID\n* if `getNodeClone` option is supplied, it will be called to get a copy of the node. It receives a TreeNode object, and should return a node object (only the data).\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Event\"\n}\n[/block]\nYou can listen to `onMoveNode` events and get the moved node, and its new location in the tree\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"options = {\\n  allowDrag: true\\n}\\n\\nonMoveNode($event) {\\n  console.log(\\n  \\t\\\"Moved\\\",\\n  \\t$event.node.name,\\n  \\t\\\"to\\\",\\n  \\t$event.to.parent.name,\\n  \\t\\\"at index\\\",\\n   \\t$event.to.index);\\n}\\n\\n<tree-root\\n\\t\\t(onMoveNode)=\\\"onMoveNode($event)\\\"\\n\\t\\t[nodes]=\\\"nodes\\\"\\n\\t\\t[options]=\\\"options\\\"></tree-root>\",\n      \"language\": \"javascript\",\n      \"name\": \"listen to onMoveNode events\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Override default behaviour\"\n}\n[/block]\nuse `actionMapping.mouse.drop` to override the default drag behaviour.\nYou can also listen to all other drag events like dragEnd, dragLeave etc.:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"options = {\\n  allowDrag: true,\\n  actionMapping: {\\n  \\tmouse: {\\n      drop: (tree:TreeModel, node:TreeNode, $event:any, {from, to}) => {\\n        // use from to get the dragged node.\\n        // use to.parent and to.index to get the drop location\\n        // use TREE_ACTIONS.MOVE_NODE to invoke the original action\\n      },\\n      dragStart?: IActionHandler,\\n      drag?: IActionHandler,\\n      dragEnd?: IActionHandler,\\n      dragOver?: IActionHandler,\\n      dragLeave?: IActionHandler,\\n      dragEnter?: IActionHandler      \\n    }\\n  }\\n}\\n\\n<tree-root\\n\\t\\t[nodes]=\\\"nodes\\\"\\n\\t\\t[options]=\\\"options\\\"></tree-root>\",\n      \"language\": \"javascript\",\n      \"name\": \"Override drag & drop action in actionMapping\"\n    }\n  ]\n}\n[/block]\nIn the drop callback, you get a 'from' and 'to' objects:\n- from:\n  - If dragging a node, then from === the dragged node\n  - If dragging something else, it is the draggedElement (see treeDrag directive below)\n\n- to:\n  - parent: the parent node\n  - index: the index inside the parent's children where the node should be dropped\n  - dropOnNode: distinguish between dropping on the node itself or the drop slot\n\n[block:api-header]\n{\n  \"title\": \"Drag and drop between trees\"\n}\n[/block]\nThis is enabled by default when dragging is enabled\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Drag a node outside of the tree\"\n}\n[/block]\nYou can use the (treeDrop) directive to allow dragging nodes to an external element.\nFor example:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<div (treeDrop)=\\\"onDrop($event)\\\"\\n     [treeAllowDrop]=\\\"allowDrop.bind(this)\\\"></div>\\n\\n  onDrop($event) {\\n    // Dropped $event.element\\n  }\\n\\n  allowDrop(element) {\\n    // Return true/false based on element\\n  }\\n\",\n      \"language\": \"javascript\",\n      \"name\": \"use (treeDrop) to drag an external element to the tree\"\n    }\n  ]\n}\n[/block]\nUse `$event.element` inside the callback.\nUse `[treeAllowDrop]` Input to specify a function that runs onDragOver, and decides if the dropping is allowed or not.\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Drag an external element into the tree\"\n}\n[/block]\nYou can use the `[treeDrag]` directive to allow dragging external elements into the tree.\nThen use a custom action to handle the drop (see [Action Mapping](doc:action-mapping) section).\n\nFor example:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"options = {\\n  actionMapping: {\\n    mouse: {\\n      drop: (tree, node, $event, {from, to}) => {\\n        console.log('drag', from, to); // from === {name: 'first'}\\n        // Add a node to `to.parent` at `to.index` based on the data in `from`\\n        // Then call tree.update()\\n      }\\n    }\\n  }\\n}\\n\\n<p [treeDrag]=\\\"{name: 'first'}\\\" [treeDragEnabled]=\\\"true\\\">Drag me!</p>\\n<p [treeDrag]=\\\"{name: 'second'}\\\">Drag me as well!</p>\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe data that you pass to `[treeDrag]` will be passed to the handler in the `from` parameter.\n\nUse `to.parent` and `to.index` to get the drop location.\nUse `to.dropOnNode` to distinguish between dropping on the node itself or the drop slot.\nIf you add a new node to the tree, you'll need to call `tree.update()` afterwards.\n\nUse `[treeDragEnabled]` boolean Input to decide if the drag is enabled or not.\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Drag to an empty tree\"\n}\n[/block]\nTo drag to an empty tree, set your nodes to an empty array.\nIf nodes is undefined or null, the drop slot will not appear.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Styling\"\n}\n[/block]\nThe following classes are available for dragging over elements, based on allowDrop:\n* is-dragging-over\n* is-dragging-over-disabled","excerpt":"","slug":"drag-drop","type":"basic","title":"Drag & Drop"}
[Options](#options) [Event](#event) [Override default behaviour](#override-default-behaviour) [Drag a node outside of the tree](#drag-a-node-outside-of-the-tree) [Drag an external element into the tree](#drag-an-external-element-into-the-tree) [Drag to an empty tree](#drag-to-an-empty-tree) [Styling](styling) [block:api-header] { "type": "basic", "title": "Options" } [/block] [block:code] { "codes": [ { "code": "options = {\n allowDrag: (node) => node.isLeaf,\n allowDrop: (element, { parent, index }) {\n // return true / false based on element, to.parent, to.index. e.g.\n return parent.hasChildren;\n },\n getNodeClone: (node) => ({\n ...node.data,\n id: uuid.v4(),\n name: `copy of ${node.data.name}`\n })\n};\n\noptions2 = {\n allowDrag: true,\n allowDrop: false\n};\n\n<tree-root\n\t\t[nodes]=\"nodes\"\n\t\t[options]=\"options\"></tree-root>", "language": "javascript", "name": "Allow drag & drop using `allowDrag` flag in tree options" } ] } [/block] Dragging: Enable dragging with `allowDrag` option (default false) accepts either a boolean or a function: * Boolean value - decides if drop is allowed or not on the tree * Function - decides on a per node basis if drop is allowed. The function receives: * node - the dragged TreeNode Dropping: Enable selective dropping with the `allowDrop` option (default true) accepts either a boolean or a function: * Boolean value - decides if drop is allowed or not on the tree * Function - decides on a per node basis if drop is allowed. The function receives: * element - the dragged element * to - drop location structure * parent - the parent node * index - the index inside the parent's children where the element is dropped Copying: The default behaviour of the tree is to copy the node when `ctrl` is pressed while dropping the node * By default the tree will shallow-clone the node data and generates a random ID * if `getNodeClone` option is supplied, it will be called to get a copy of the node. It receives a TreeNode object, and should return a node object (only the data). [block:api-header] { "type": "basic", "title": "Event" } [/block] You can listen to `onMoveNode` events and get the moved node, and its new location in the tree [block:code] { "codes": [ { "code": "options = {\n allowDrag: true\n}\n\nonMoveNode($event) {\n console.log(\n \t\"Moved\",\n \t$event.node.name,\n \t\"to\",\n \t$event.to.parent.name,\n \t\"at index\",\n \t$event.to.index);\n}\n\n<tree-root\n\t\t(onMoveNode)=\"onMoveNode($event)\"\n\t\t[nodes]=\"nodes\"\n\t\t[options]=\"options\"></tree-root>", "language": "javascript", "name": "listen to onMoveNode events" } ] } [/block] [block:api-header] { "type": "basic", "title": "Override default behaviour" } [/block] use `actionMapping.mouse.drop` to override the default drag behaviour. You can also listen to all other drag events like dragEnd, dragLeave etc.: [block:code] { "codes": [ { "code": "options = {\n allowDrag: true,\n actionMapping: {\n \tmouse: {\n drop: (tree:TreeModel, node:TreeNode, $event:any, {from, to}) => {\n // use from to get the dragged node.\n // use to.parent and to.index to get the drop location\n // use TREE_ACTIONS.MOVE_NODE to invoke the original action\n },\n dragStart?: IActionHandler,\n drag?: IActionHandler,\n dragEnd?: IActionHandler,\n dragOver?: IActionHandler,\n dragLeave?: IActionHandler,\n dragEnter?: IActionHandler \n }\n }\n}\n\n<tree-root\n\t\t[nodes]=\"nodes\"\n\t\t[options]=\"options\"></tree-root>", "language": "javascript", "name": "Override drag & drop action in actionMapping" } ] } [/block] In the drop callback, you get a 'from' and 'to' objects: - from: - If dragging a node, then from === the dragged node - If dragging something else, it is the draggedElement (see treeDrag directive below) - to: - parent: the parent node - index: the index inside the parent's children where the node should be dropped - dropOnNode: distinguish between dropping on the node itself or the drop slot [block:api-header] { "title": "Drag and drop between trees" } [/block] This is enabled by default when dragging is enabled [block:api-header] { "type": "basic", "title": "Drag a node outside of the tree" } [/block] You can use the (treeDrop) directive to allow dragging nodes to an external element. For example: [block:code] { "codes": [ { "code": "<div (treeDrop)=\"onDrop($event)\"\n [treeAllowDrop]=\"allowDrop.bind(this)\"></div>\n\n onDrop($event) {\n // Dropped $event.element\n }\n\n allowDrop(element) {\n // Return true/false based on element\n }\n", "language": "javascript", "name": "use (treeDrop) to drag an external element to the tree" } ] } [/block] Use `$event.element` inside the callback. Use `[treeAllowDrop]` Input to specify a function that runs onDragOver, and decides if the dropping is allowed or not. [block:api-header] { "type": "basic", "title": "Drag an external element into the tree" } [/block] You can use the `[treeDrag]` directive to allow dragging external elements into the tree. Then use a custom action to handle the drop (see [Action Mapping](doc:action-mapping) section). For example: [block:code] { "codes": [ { "code": "options = {\n actionMapping: {\n mouse: {\n drop: (tree, node, $event, {from, to}) => {\n console.log('drag', from, to); // from === {name: 'first'}\n // Add a node to `to.parent` at `to.index` based on the data in `from`\n // Then call tree.update()\n }\n }\n }\n}\n\n<p [treeDrag]=\"{name: 'first'}\" [treeDragEnabled]=\"true\">Drag me!</p>\n<p [treeDrag]=\"{name: 'second'}\">Drag me as well!</p>", "language": "javascript" } ] } [/block] The data that you pass to `[treeDrag]` will be passed to the handler in the `from` parameter. Use `to.parent` and `to.index` to get the drop location. Use `to.dropOnNode` to distinguish between dropping on the node itself or the drop slot. If you add a new node to the tree, you'll need to call `tree.update()` afterwards. Use `[treeDragEnabled]` boolean Input to decide if the drag is enabled or not. [block:api-header] { "type": "basic", "title": "Drag to an empty tree" } [/block] To drag to an empty tree, set your nodes to an empty array. If nodes is undefined or null, the drop slot will not appear. [block:api-header] { "type": "basic", "title": "Styling" } [/block] The following classes are available for dragging over elements, based on allowDrop: * is-dragging-over * is-dragging-over-disabled