13

I have table rows that are sortable depending on whether certain radio buttons are checked or not. The sortables are initialized on document.ready as follows:

$(document).ready(function() {
    // Return a helper with preserved width of cells
    // handy code I got from http://lanitdev.wordpress.com/2009/07/23/make-table-rows-sortable-using-jquery-ui-sortable/
    var fixHelper = function(e, ui) {
        ui.children().each(function() {
            $(this).width($(this).width());
        });
        return ui;
    };
    // #opts = table id; tr.ui-state-disabled class = rows not sortable
    $("#opts tbody").sortable({
        items: 'tr:not(.ui-state-disabled)',
        cursor: 'crosshair',
        helper: fixHelper
    }).disableSelection();
});

I have the following function attached to the radio buttons (ids prefixed "active_") onchange which either adds or removes the ui-state-disabled class attribute from table rows (dynamic ids prefixed "opt_"):

    var toggleDrag = function(i){
    if ($('#active_'+i+'-0').is(':checked')) {
        $('#opt_'+i).addClass('ui-state-disabled');
    }
    if ($('#active_'+i+'-1').is(':checked')) {
        $('#opt_'+i).removeClass();
    }
    $("#opts tbody").sortable("option", "items", "tr:not(.ui-state-disabled)");
    //$("#opts tbody").sortable("refresh");
    //alert($('#opt_'+i).attr('class')); - alert indicates that the class attribute is being changed
    //$("#opts tbody").sortable("option", "cursor", "auto"); - this works!
}

If I select a radio button that should make a previously un-sortable row sortable, it works and I can drag and drop the row. The problem is if I select a radio button to make a row that previously was sortable, un-sortable, I can still drag and drop it. The setter .sortable("option", "items", "tr:not..etc") doesn't appear "un-register" a row if it was previously sortable. I also tried .sortable("refresh") with no luck. And I have checked to see if the class attribute is being changed with an alert and it is.

Any help with this would be greatly appreciated.

5 Answers 5

15

I ran into the same problem, that the items option doesn't seem to remove items which had been previously enabled.

The cancel option, however, does. Note that the disabled items will shift around to make room for the sortable ones (the spot is still available as a drop target), but dragging the disabled items themselves will not work. Using a disabled class also makes it easy to change the style based on whether or not the item is sortable (see on jsfiddle).

The code here is partially based on Bah Bah the Lamb's answer, but it has been greatly tidied and simplified.

The html:

<ul id="sorted-list">
   <li>
       <p><input type="checkbox" checked="true" /> Item 1</p>
    </li>
   <li>
       <p class="disabled"><input type="checkbox" /> Item 2</p>
   </li>
   <li>
       <p><input type="checkbox" checked="true" /> Item 3</p>
   </li>
</ul>

The jQuery:

$("#sorted-list").sortable({
    cancel:".disabled"
});

// add or remove the 'disabled' class based on the value of the checkbox
$("#sorted-list input").click(function() {
    if (this.checked) {
        $(this.parentElement).removeClass("disabled");
    } else { 
        $(this.parentElement).addClass("disabled");
    }
});

The CSS:

li {
  border: 1px solid #aaa;
  background-color: #eee;
  color:#555;
  padding: 5px;
}

.disabled {
  color:#ddd;
}
Sign up to request clarification or add additional context in comments.

2 Comments

using cancel works for me, even without making room when dragging over like you mentioned - Probably fixed since your answer.
@Ronny I think there is a way to configure the lack of drop-target, but I can't figure it out just now.
6

I had a similar problem and found an easy solution (but in my example I am using a sortable ul not a table, as there is more freedom with mark-up in ul's).

The idea behind it is to leave the list and all its items sortable, but remove the handle, thus disabling the individual item's ability to sort, as seen in this code

<ul id="sorted-list">
    <li>
        <div class="handle sortable">
            <p>Item 1</p>
            <input type="button" value="Disable Sort" />
        </div>
    </li>
    <li>
        <div class="handle sortable">
            <p>Item 2</p>
            <input type="button" value="Disable Sort" />
        </div>
    </li>
    <li>
        <div class="handle sortable">
            <p>Item 3</p>
            <input type="button" value="Disable Sort" />
        </div>
    </li>
    <li>
        <div class="handle sortable">
            <p>Item 4</p>
            <input type="button" value="Disable Sort" />
        </div>
    </li>
</ul>
<script>
    $("#sorted-list").sortable({
        items: "li",
        handle: ".handle.sortable"
    });
    $("#sorted-list").find("input").click(function() {
        if ($(this).closest(".handle").hasClass("sortable"))
            $(this).val("Enable Sort").closest(".handle").removeClass("sortable");
        else $(this).val("Disable Sort").closest(".handle").addClass("sortable");
    });
</script>

Comments

4

Try using the disabled option. http://jqueryui.com/demos/sortable/#option-disabled

3 Comments

Forgot to mention I did try: $("#opts tbody tr.ui-state-disabled").sortable("option","disabled", true); and it didn't work but then thought its the table thats .sortable so how would I target the row with the disabled option
I've also since populated a hidden form element with the sortable array and it does exclude rows that have been "un-sorted" even though they remain drag and dropable so maybe I should explicitly use drag and dropable functions as well though I thought sortable would take care or it all. Its 10.30pm where I am so I'll stop for the night. Thanks for your input.
Can you post the full code, or a link to a test page (javascript, HTML, CSS)?
2

I've been trying to do the same thing. I really wanted the items feature rather than disabled. As pointed out above, there is a weakness in the jQueryUI implementation whereby the sortable don't refresh the items list should the items matched by the selectors change.

To get around this, I simply destroyed and reinstantiated the sortabled. I've adapted Hannele's JSfiddle to demonstrate (http://jsfiddle.net/Sxg8D/140/).

$("#sorted-list").sortable({
    items:"li:not(.disabled)"
});

$("#sorted-list input").click(function() {
    if (this.checked) {
        $(this.parentElement).removeClass("disabled");
    } else { 
        $(this.parentElement).addClass("disabled");
    }

    $("#sorted-list")
        .sortable( "destroy" )
        .sortable({
            items:"li:not(.disabled)"
        });
});

Comments

0

I know this is old, but had a similar problem. I had my sortable items in groupings. I wanted certain groups to be sortable anywhere and some to only be sortable to a subsection of groups.

<div id="sortBlock">
    <div id="noSort class="itemBlock">
        <div class="item">
        <div class="item">
    </div>
    <div id="canSort" class="itemBlock">
        <div class="item">
        <div class="item">
    </div>
</div>

Items from noSort can sort anywhere. Items from canSort can only sort into other canSort blocks.

$("#sortBlock").sortable({
    items: "> div.itemBlock > .item"   // this makes sure only the sub items will be sortable
});

Then setting this rule after the init seemed to do the trick.

$("#sortBlock").sortable( "option", "items", "> div:not(#noSort) > .item");

Was trying to do it dynamically in the start/stop events, but this did the trick, not sure "why", so test well.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.