【问题标题】:Using JQuery Multisortable plus filtering a list使用 JQuery Multisortable 加上过滤列表
【发布时间】:2020-11-09 02:41:21
【问题描述】:

那么,问题来了……

我有两个列表。我希望用户能够从左侧的一个列表中拖动以在右侧构建一个新列表,但也希望让他们能够过滤左侧列表。左边的列表可能很长,所以我也希望它们能够多选和拖动。

对于多选我使用jQuery multisortable

这是一个jsFiddle 来展示我想要实现的目标。

最终目标是为构建的列表构建一个逗号分隔的字符串。如果您在“a”上过滤列表,多选结果,您将看到所有列表项都被拖到正确的列表中 - 甚至是过滤器隐藏的过滤项目之间的那些 - 我该如何解决这个问题?

任何帮助表示赞赏!

以下示例使用的是 Bootstrap 4

编辑:查看 DOM 我可以看到当 SHIFT 键用于多选项目时,JQuery 过滤器添加了一个类“multiselectable-shift”,因此尝试添加选项...

items: '> li:not("multiselectable-shift")'

...到可排序的,仍然没有快乐。使用 control 键或 meta kay 没问题,问题只是 shift 键。

<script>
  jQuery(function($) {
    $('ul.connectedSortable').multisortable({
      selectedClass: 'highlight'
    });
    $('ul#sortable1').sortable({
      connectWith: 'ul#sortable2',
      update: function() {
        callListIds = "";
        $("ul#sortable2 li").each(function() {
          callListIds += $(this).attr("id") + ",";
        })
        callListIds = callListIds.replace(/,\s*$/, "");
        $("#listIdResult").html(callListIds);
      }
    });
    $('ul#sortable2').sortable({
      connectWith: 'ul#sortable1',
      update: function() {
        callListIds = "";
        $("ul#sortable2 li").each(function() {
          callListIds += $(this).attr("id") + ",";
        })
        callListIds = callListIds.replace(/,\s*$/, "");
        $("#listIdResult").html(callListIds);
      }
    });
  });
// Search field
$(document).ready(function() {
  $("#search").on("keyup", function() {
    var value = $(this).val().toLowerCase();
    $("#sortable1 li").filter(function() {
      $(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
    });
  });
}); </script>
.highlight { 
  background-color: #AABFF3;
} 
<html lang="en">
<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
  <link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet" />
  <script   src="https://rawgithub.com/shvetsgroup/jquery.multisortable/master/src/jquery.multisortable.js"></script>
  <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" />
  <style>
    .highlight {  background-color: #AABFF3; }
  </style>
</head>
  <body>
    <input type="hidden" name="callListIds" id="callListIds" value="">
    <div class="d-flex justify-content-center w-90 mx-auto d-block pt-5">
      <div class="container w-40 float-left">
        <input type="search" class="form-control" name="search" id="search" placeholder="search...">
        <ul id="sortable1" class="connectedSortable list-group" style="min-height:100%">
          <li id="ls1" class="list-group-item w-100 p-1">ABC</li>
          <li id="ls2" class="list-group-item w-100 p-1">DEF</li>
          <li id="ls3" class="list-group-item w-100 p-1">AGH</li>
          <li id="ls4" class="list-group-item w-100 p-1">HIJ</li>
          <li id="ls5" class="list-group-item w-100 p-1">KLM</li>
          <li id="ls6" class="list-group-item w-100 p-1">AOP</li>
        </ul>
      </div>
      <div class="container w-40 float-right border ml-1">
        <ul id="sortable2" class="connectedSortable list-group" style="min-height:100%">
        </ul>
      </div>
    </div>
    <p class="p-2 text-center">Resulting comma delimited String:
      <span id="listIdResult"></span></p>
    </body

【问题讨论】:

  • 当我测试你的小提琴时,通过运行过滤器,然后选择多个项目并将它们拖过来,我只会得到我选择的项目。无法按照您的描述复制它。
  • 我能够通过非常具体的步骤复制它。 1)单击和项目以选择它 2)过滤“a” 3)Shift-单击一个项目 4)拖动项目。我得到了 5 个项目而不是 2 个。如果我先过滤然后选择,它会按预期工作。
  • 所以问题是当您按住 Shift 键单击选择一个组时,它会选择所有项目而不仅仅是可见项目。这是对多选的限制,您需要查看是否使用:visible 选择器。
  • 谢谢你们的cmets。是的,问题只是 SHIFT 键。如果您过滤“a”,它会过滤到三个项目。当您单击第一个项目,然后单击第三个项目并拖动时,所有项目(包括被过滤器隐藏的项目)都会被拖动。

标签: javascript jquery jquery-ui jquery-multisortable


【解决方案1】:

基本上,代码中存在逻辑问题[https://github.com/shvetsgroup/jquery.multisortable/blob/master/src/jquery.multisortable.js 44-56]:

if (e.shiftKey) {
  var last_shift_range = parent.find('.multiselectable-shift');

  last_shift_range.removeClass(options.selectedClass).removeClass('multiselectable-shift');

  var shift_range;
  if (prevIndex < myIndex) {
    shift_range = item.prevUntil('.multiselectable-previous').add(prev).add(item);
  }
  else if (prevIndex > myIndex) {
    shift_range = item.nextUntil('.multiselectable-previous').add(prev).add(item);
  }
  shift_range.addClass(options.selectedClass).addClass('multiselectable-shift');
}

基本上,它在创建范围时忽略了items 选项。所以当你像这样配置时:

$(el).multiselect({
  items: "li:visible"
});

Shift Click 事件将创建一个 Range 并包含所有列表项(无论它们是否可见)。我尝试了一些解决方法并将 Fiddle 改进为:

https://jsfiddle.net/Twisty/sjg5u1ty/56/

JavaScript

jQuery(function($) {
  $.fn.filterList = function(t) {
    console.log("Filter For:", t);
    $("> li", this).each(function(i, el) {
      $(el).toggle($(el).text().toLowerCase().indexOf(t.toLowerCase()) > -1);
    });
    $(this).multisortable("option", "items", "> li:visible").multisortable("refresh");
  }

  function listToString(el) {
    return $(el).sortable("toArray").toString();
  }

  $('ul.sortable').multisortable({
    selectedClass: 'highlight'
  }).sortable({
    connectWith: ".sortable",
    update: function(e, ui) {
      $("#listIdResult").html(listToString(this));
    }
  });

  $("#search").on("input", function(e) {
    $("#sort-1").filterList($(this).val());
  });
});

理论上,这应该有效,但它没有。过滤列表后,它应该更新选项并刷新可以选择的内容。我不确定这是否可以通过预设的插件“修复”,并且由于它已经 7 年没有更新,我怀疑是否会有修复。

可能有更好的答案,但我现在没有。如果我遇到任何问题,将调查并更新此答案。

【讨论】:

  • 感谢 Twisty!我会离开几天,但我认为这可能是正确的答案。问题似乎确实是插件代码,现在我刚刚将它设置为返回 if(e.shiftKey) 你的代码比我的要好得多!真的,真的很感谢你所花的时间!
猜你喜欢
  • 2018-08-20
  • 2014-01-08
  • 2013-07-13
  • 2012-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-17
相关资源
最近更新 更多