JavaScript Drag and Drop example 3

More...

School timetable is example of how to use REDIPS.drag library. Page layout contains two tables: left table with school subjects and timetable on the right. After subject is placed to the timetable, button in the same color will be displayed next to the subject (clone object).

Arts
Biology
Chemistry
English
Ethics
History
IT
Mathematics
Physics
Trash
Drag school subjects to the timetable (clone subjects with SHIFT key)

Please note two checkboxes in the upper left corner of timetable. First checkbox is turned on by default to enable cloning subjects across a week. You can turn it off for placing single subject to the timetable. If second checkbox is checked, then "subject report" will pop up if report button (button next to subjects in left table) is clicked. At the same time, all other subjects will be hidden. Clicking on any element in left or right table will show up all elements.

The following code shows myhandler_dropped() event handler (with logic for cloning DIV elements across a week).

rd.myhandler_dropped = function () {
    var obj_old = rd.obj_old,                   // original object
        target_cell = rd.target_cell,           // Target cell
        target_row = rd.target_cell.parentNode, // Target row
        marked_cell = rd.marked_cell,           // marked cells
        mark_cname = rd.mark_cname,             // name of marked cells
        i, obj_new, mark_found;                 // local variables
    // if checkbox is checked and original element is clone type then
    // clone school subject to the week
    if (document.getElementById('week').checked === true
        && obj_old.className.indexOf('clone') > -1) {
        // loop through table cells
        for (i = 0; i < target_row.cells.length; i++) {
            // skip if table cell is not empty (true for cell where
            // element is currently dropped)
            if (target_row.cells[i].childNodes.length > 0) {
                continue;
            }
            // search for "mark" class name
            mark_found = target_row.cells[i].className.indexOf(mark_cname) > -1 ? true : false;
            // if current cell is marked and access type is 'deny' or current cell
            // is not marked and access type is "allow" then skip this table cell
            if ((mark_found === true && marked_cell === 'deny') ||
                (mark_found === false && marked_cell === 'allow')) {
                continue;
            }
            // clone DIV element
            obj_new = rd.clone_div(obj_old);
            // append to the table cell
            target_row.cells[i].appendChild(obj_new);
        }
    }
    // print message only if target and source table cell differ
    if (rd.target_cell !== rd.source_cell) {
        print_message('Content has been changed!');
    }
    // show / hide report buttons
    report_button();
};

Source code (including school timetable with save/recall table using PHP and MySQL) and detailed description of library can be found on Drag and drop table content with JavaScript.

This entry was posted on February 22, 2010 and is filed under Drag and Drop, JavaScript

Related posts

94 Responses to JavaScript Drag and Drop example 3

  1. dbunic says:

    @Sudeep - please pay attention to checkbox in the upper left corner of timetable. If checkbox is checked then DIV element will be cloned across whole week. Hope this functionality is what you looking for ...

  2. Sudeep says:

    @dbunic - Thanks, that is exactly what I was looking for. Missed it originally. Awesome stuff here - very well compiled !

  3. Rich says:

    Hi there, Is it possible to make drag into a class? Thanks!

  4. Rich says:

    Hi again, I have one other question. I have a table that I have created using spry, that pulls in some data from an xml file. The code seems to clash when inside the 'drag' div.

    The dragging ability disappears when nested inside drag div for some reason - Are there known issues with spry?? Im just putting together a very basic version onto my site to illustrate the issue.

    Thanks mate,

    Richard

  5. dbunic says:

    @Rich - I'm not sure what you mean by making drag into a class. Can you give a little bit more details ...

    Regarding spry - maybe the problem is in dynamically loading content to the HTML table. If so, you should run REDIPS initialization after that to rescan new table state. Maybe DIV element lost attached onmousedown event handler and dragging ability disappears. That's only guessing and any example that can illustrate the problem will be welcomed.

  6. Rich says:

    Thanks for your reply Dbunic. I have put up an example here: http://richyobrien.com/testBoard/tableTest2.html

    This line of code seems to be the culprit. If I remove spry:region="ds1" functionality is restored.

    Nevermind the class question, I had just confused myself there while trying something that you had already answered in a previous exmaple. :)

    Thanks again!

    Rich

  7. dbunic says:

    @Rich - Hi, it seems that spry somehow overwrite DIV elements after REDIPS initialization. Please try this lines:

    var ds1 = new Spry.Data.XMLDataSet("data2.xml", "customers/customer",{sortOnLoad:"lot" ...
    var ds1 = new Spry.Data.XMLDataSet("data2.xml", "customers/customer",{sortOnLoad:"tag" ...
    var ds1 = new Spry.Data.XMLDataSet("data2.xml", "customers/customer",{sortOnLoad:"sire" ...
    var ds1 = new Spry.Data.XMLDataSet("data2.xml", "customers/customer",{sortOnLoad:"dam" ...
    ds1.setColumnType("lot", "number");
    ds1.setColumnType("tag", "number");
    ds1.setColumnType("sire", "string");
    ds1.setColumnType("dam", "number");
    

    move inside window.onload to look like this:

    window.onload = function () {
        var ds1 = new Spry.Data.XMLDataSet("data2.xml", "customers/customer",{sortOnLoad:"lot" ...
        var ds1 = new Spry.Data.XMLDataSet("data2.xml", "customers/customer",{sortOnLoad:"tag" ...
        var ds1 = new Spry.Data.XMLDataSet("data2.xml", "customers/customer",{sortOnLoad:"sire" ...
        var ds1 = new Spry.Data.XMLDataSet("data2.xml", "customers/customer",{sortOnLoad:"dam" ...
        ds1.setColumnType("lot", "number");
        ds1.setColumnType("tag", "number");
        ds1.setColumnType("sire", "string");
        ds1.setColumnType("dam", "number");
        // initialization
        REDIPS.drag.init();
        ...
        ...
    

    I'll keep my fingers crossed. If the problem will still exist then I will look further.
    Cheers!

  8. Rich says:

    Thank you for your help!

    Unfortunately this doesn't seem to work. This is probably a fairer representation of what I am trying to achieve http://www.richyobrien.com/testBoard/tb4.html It is very similar to the first example I gave, but once I update the xml the 'auction' board automatically updates. Again it is the "spry:detailregion="dsAuctionData dsOne" which causes the issue. In both instances the error "Failed to retrieve data set (dsOne) for spry:repeat " is returned.

    Thanks mate, your help and time is very much appreciated.

  9. dbunic says:

    OK, I think you should define observer to the region with onPostUpdate notification. This observer should run REDIPS initialization instead of window.onload. I will suggest to modify window.onload to normal JavaScript function. For example rename it to "redips_drag". Next (only for testing purpose) place a button to your page with onclick event to fire "redips_drag" function. Reload the page and try dragging. Dragging will not work. Next, click on the button and dragging should work.

    The same scenario will be with observer function. Observer will start "redips_drag" after region has regenerated its code and inserted it into the document.

    Please see details how to attach observer at the bottom of Working with Spry XML Data Sets. Just search for addObserver() in "Region observer notifications".

    Hope this will help.

    Sorry, I forgot to mention that you move out your lines out of window.onload as it was in previous case.

  10. Rich says:

    Great!! Thank you! I have only had a quick moment to play with it so far, but it looks like you were bang on :) I am swinging above my weight a bit with this project, but I'm learning some fantastic things.

    Cheers,

    Rich

  11. I need to use "position:fixed" for the destination table - so it won;t scroll off the screen when I have a large list of fields. When I try it kills the drag function. Is it possible?

  12. dbunic says:

    @Howiw Wolowitz - In latest redips2.tar.gz package you can find example 10 - sticky tables. Hope this is what you are looking for ...

  13. Andrew says:

    Excuse my ignorance but is there anyway to drag a Subject and drop it in to multiple adjacent timeslots, i.e. drag Physics in to Wednesday 9:00 and 10:00 without having to select Physics twice from the Subject list?

  14. dbunic says:

    @Andrew - REDIPS.drag library focuses only one target cell. In a moment when user releases mouse button, myhandler_dropped() can perform some additional work - like placing subject across whole week or placing subject to 9:00 and 10:00. On the other hand, you can enable cloning elements with CTRL key:

    REDIPS.drag.clone_ctrlKey = true;
    

    So, after element is dropped to the Wednesday 9:00, you can press CTRL key and click with left mouse button on the previously dropped element. Instead of moving, element will be cloned immediately - not needed to drag new element from Subject list. To enable cloning with CTRL key, place REDIPS.drag.clone_ctrlKey line after initialization. You can peek to the source of index.html in example 5 to see how to enable CTRL cloning.

  15. Andrew says:

    Thanks for that, the CTRL cloning works great, one more thing is it possible to find the Row and Column of the target cell, as I want to pass this info to another window so as I can add extra information such as teacher/classroom etc.

    Forgive my ignorance has I'm really just a COBOL programmer!

  16. dbunic says:

    @Andrew - No problem. If you need to know row and column of DIV element in a moment of dropping, you can use myhandler_dropped() event handler:

    REDIPS.drag.myhandler_dropped = function () {
        // define current row and current cell
        var ri = REDIPS.drag.current_cell.parentNode.rowIndex,
            ci = REDIPS.drag.current_cell.cellIndex;
        // display current row and current cell
        document.getElementById('message').innerHTML = 'Dropped: ' + ri + ' ' + ci;
    }
    

    On the other hand, if you want to accept row and column index of DIV elements on server side - PHP page, please see foreach loop in save.php (save.php is placed in example03 directory of redips2.tar.gz package).

  17. arzozeus says:

    Hi, I love this tutorial and I would do a button which can help me to check which row and cell is having what clone. Below is my coding

    function check() {
        if (document.getElementById('aaa') == null) {
            var msg = "null";
            alert(msg);
        } else {
            var msg = "not null";
            alert(msg);
        }
    }
    

    My coding only will come with alert message "not null", but I didn't not put any clone in the first cell, it should come out "null" as the alert message. Hope you can help me, thank you.

  18. dbunic says:

    @arzozeus - Your code will search for element with id="aaa" on DOM document regardless to the element position. If you are interested for content of the first table cell, maybe you can set ID to the first cell (like id="first_cell") and search for DIV elements beneath that element:

    // search for div elements in first table cell
    var content = document.getElementById('first_cell').getElementsByTagName('div');
    // if content exists
    if (content.length > 0) {
        ...
        ...
    

    On the other hand, if you want to scan whole table for dropped content then upper solution is not so appropriate. Please take a look save_content() function inside redips-drag.js and you will see how to scan table content with several "for" loops.

  19. Havard says:

    Thanks for sharing this work, it's exactly what I've been looking for. When using this example, and adding even more days (11 in total), it isn't possible to drop the subjects on the "new" days. Is there some limitation built into the code which doesn't allow to use more cols than five?

  20. dbunic says:

    @Havard - No, there isn't any kind of limitation but tables should be contained inside DIV id="drag". My guess is that size of dragging area is smaller then your tables. Please try to make dragging area visible (just define border style):

    #drag {border: 1px solid lime;}

    If that's the case, you will only have to increase size of DIV (with width and height properties) and the problem will go away.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

In case of posting HTML tags or JavaScript code please convert special characters to HTML entities.
Especially pay attention to convert "<" to "&lt;" character!