Add custom drop event to TreeView node to handle drops from File Explorer

4 posts, 1 answers
  1. Scott
    Scott avatar
    19 posts
    Member since:
    Mar 2011

    Posted 16 Jun 2015 Link to this post

    I'm trying to add a custom drop event to each tree view node so that I can handle the 'drop' event when a file is dropped onto the node element from Windows File Explorer.  My html code (with the style section removed) looks like this:

     

    <div id="example">
            <div class="demo-section k-header">
                <div class="box-col" style="width: 300px">
                    <h4>Select a node</h4>
                    <div class="files"
                         data-role="treeview"
                         data-drag-and-drop="false"
                         data-text-field="name"
                         data-spritecssclass-field="type"
                         data-bind="visible: isVisible,
                                source: files,
                                events: { dataBound: onDataBound }"></div>
                </div>
            </div>
            
            <script>
                $(document).ready(function ()
                {
                    $("#treeview").kendoTreeView();
                });
            </script>
        </div>

     

    I'm binding the view model like this:

    <script>
        var viewModel = kendo.observable({
            isVisible: true,
            onDataBound: function (e)
            {
                if (e.node)
                {
                    var dataItem = e.sender.dataItem(e.node);
     
                    dataItem.bind('drop', function (e1)
                    {
                        alert('dropped on item');
                    });
                }
            },
            files: kendo.observableHierarchy(jobBookAPI.directoryContents)
        });
        kendo.bind($("#example"), viewModel);
     
    </script>

    My data looks like this:

    var jobBookAPI = new function ()
    {
        // Public data
     
        this.directoryContents =
            [
                {
                    name: "My Web Site", type: "folder", expanded: true, items:
                    [
                        {
                            name: "images", type: "folder", expanded: true, items:
                            [
                                { name: "logo.png", type: "image" },
                                { name: "my-photo.jpg", type: "image", id: 12345 }
                            ]
                        },
                        {
                            name: "resources", type: "folder", expanded: true, items:
                            [
                                { name: "resources", type: "folder" },
                                { name: "zip", type: "folder" }
                            ]
                        },
                        { name: "about.html", type: "html" },
                        { name: "index.html", type: "html" }
                    ]
                }
            ];
     
    };
     

     

    The drop event does not fire when I drag a file onto a node.  I've tried replacing 'drop' with 'click' just to see if I can fire a click event, but that event doesn't fire when a node is clicked.  I think that what I'm trying to do should be possible because I've use this same method with simple DIV elements and files dropped on them from File Explorer cause the drop event to fire perfectly.

    Any ideas what I'm doing wrong?

    Thanks. 

     

     

  2. Scott
    Scott avatar
    19 posts
    Member since:
    Mar 2011

    Posted 16 Jun 2015 in reply to Scott Link to this post

    I wasn't able to come up with a solution within the onDataBound event, but I was able to make it work by enumerating each node and adding the drop event to it after binding the data.  Like this:

     

    var viewModel = kendo.observable({
        isVisible: true,
        files: kendo.observableHierarchy(jobBookAPI.directoryContents)
    });
    kendo.bind($("#example"), viewModel);
     
    // Makes sure the dataTransfer information is sent when we handle file drops
    jQuery.event.props.push('dataTransfer');
     
    var allNodes = $('#example').find(".k-top,.k-mid,.k-bot");
    for (var i = 0; i < allNodes.length; i++)
    {
        $(allNodes[i]).bind('dragenter', function ()
        {
            $(this).css({ 'box-shadow': 'inset 0px 0px 20px rgba(0, 0, 0, 0.1)', 'border': '4px dashed #bb2b2b' });
            return false;
        });
     
        // Must handle dragover or drop won't fire.
        $(allNodes[i]).bind('dragover', function ()
        {
            return false;
        });
     
        $(allNodes[i]).bind('dragleave', function (e)
        {
            $(this).css({ 'box-shadow': 'none', 'border': 'none' });
            return false;
        });
     
        $(allNodes[i]).bind('drop', function (e)
        {
            $(this).css({ 'box-shadow': 'none', 'border': 'none' });
            if (e.dataTransfer)
            {
                var files = e.dataTransfer.files;
                alert('dropped on item outer');
            }
            return false;
        });
    }

  3. Kendo UI is VS 2017 Ready
  4. Scott
    Scott avatar
    19 posts
    Member since:
    Mar 2011

    Posted 16 Jun 2015 in reply to Scott Link to this post

    Now the problem is that I seem to have no way to match the target node of the drop to its data source in the drop handler:

     

    $(allNodes[i]).bind('drop', function (e)
        {
            $(this).css({ 'box-shadow': 'none', 'border': 'none' });
            if (e.dataTransfer)
            {
                var files = e.dataTransfer.files;
               // How do I match the e.target back to the data?
                alert('dropped on item outer');
            }
            return false;
        });

     

    The div element in e.target contains no uid.  I could dig through the spans to grab the node name but that wouldn't work if there were two nodes of the same name in different branches.  I keep seeing code like this:  var treeView = $("#treeView").data("kendoTreeView"); on forum posts but that always returns null when binding to a view model.  Any way I can make this work?

     

  5. Answer
    T. Tsonev
    Admin
    T. Tsonev avatar
    2772 posts

    Posted 19 Jun 2015 Link to this post

    Hello,

    Please accept my apologies for the delayed response.

    Your last snippet is pretty close to what I would recommend. The event handler should go on the "k-item" element instead as that's what holds the uid.
    Also, your TreeView is missing an ID. That's why you're unable to get its instance.
    <div class="files" id="treeview" ...
    var treeView = $("#treeview").kendoTreeView();


    $("#example .k-item")
      .bind('drop', function (e)
        {
            if (e.dataTransfer)
            {
                var files = e.dataTransfer.files;
                var dataItem = treeView.dataItem(this);
                ...
            }
        });

    I hope this helps.

    Regards,
    T. Tsonev
    Telerik
     
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
     
Back to Top
Kendo UI is VS 2017 Ready