动态启用/禁用jQuery可排序项目

13

我有一些表格行,取决于某些单选按钮是否被选中而可排序。这些可排序项将在document.ready初始化,如下所示:

$(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();
});

我有一个函数附加在单选按钮(id以"active_"为前缀)的onchange事件上,它会从表格行(动态id以"opt_"为前缀)中添加或删除ui-state-disabled类属性:

我有一个与单选按钮相关联的函数(ids前缀为“active_”),该函数将添加或删除表格行(动态ids前缀为“opt_”)的ui-state-disabled类属性:

    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!
}
如果我选中一个单选按钮,应该会使以前无法排序的行变得可排序,这样它就可以被拖放了。问题在于,如果我选择一个单选按钮使一行先前变成不可排序,我仍然可以拖放它。使用setter .sortable("option", "items", "tr:not..etc") 似乎不能“注销”已经被排序的行。我也尝试过用 .sortable("refresh"),但没有成功。我已经检查过类属性是否被更改,弹出了一个警报。

非常感谢任何帮助。

5个回答

15

我遇到了同样的问题,即items选项似乎无法删除先前启用的项目。

然而,cancel选项可以。请注意,禁用的项目将移动以为可排序的项目腾出空间(该位置仍然可作为放置目标),但是拖动禁用的项目本身将不起作用。使用disabled类还可以根据项目是否可排序轻松更改样式(请参见jsfiddle)。

这里的代码部分基于Bah Bah the Lamb的答案,但已经大大简化和整理。

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>

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");
    }
});

这段CSS代码:

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

.disabled {
  color:#ddd;
}

使用 cancel 对我很有效,即使没有像您提到的那样在拖动时腾出空间 - 可能由于您的答案已经修复了。 - Ronny
@Ronny 我认为有一种方法可以配置缺少拖放目标,但我现在无法弄清楚。 - Hannele

6

我曾经遇到类似的问题,找到了一个简单的解决方案(但在我的示例中,我使用可排序的ul而不是表格,因为在ul中有更多的标记自由度)。

它的思想是保持列表及其所有项目的可排序性,但删除手柄,从而禁用单个项目的排序功能,如下所示的代码。

<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>

4

忘了提到我已经尝试过:$("#opts tbody tr.ui-state-disabled").sortable("option","disabled", true); 但它没有起作用,然后我想这是可排序的表格,那么我该如何定位带有禁用选项的行。 - annette
我已经将可排序数组填充到了一个隐藏的表单元素中,它排除了那些已经“取消排序”的行,即使它们仍然可以拖放,所以也许我应该明确地使用拖放功能,尽管我认为可排序功能会处理所有这些。现在是晚上10:30,我今晚就到这里。感谢您的帮助。 - annette
请问您能否发布完整的代码或者一个测试页面的链接(包括 JavaScript、HTML 和 CSS)? - matthewpavkov

2
我一直在尝试做同样的事情。我真的希望启用项目功能而不是禁用它。正如上面指出的那样,jQueryUI 的实现存在一个弱点,即如果由选择器匹配的项目发生更改,则可排序列表不会刷新项目列表。
为了解决这个问题,我只需销毁并重新实例化可排序列表。我已经修改了 Hannele 的 JSfiddle 来演示(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)"
        });
});

0

我知道这是老问题,但我也遇到了类似的问题。我的可排序项目分组排列。我希望某些组可以在任何地方进行排序,而有些组只能在特定的子组中进行排序。

<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>

noSort 中的项目可以在任何地方排序。canSort 中的项目只能排序到其他 canSort 块中。

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

然后在初始化之后设置这个规则似乎就解决了问题。

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

尝试在启动/停止事件中动态执行,但这样做并没有起作用,不确定原因,所以要进行充分的测试。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接