Фильтр KendoUI TreeView

Я использую treeview KendoUI и хочу дать пользователю возможность его фильтровать. Существует даже демо, которое делает то, что я хочу (http://demos.kendoui.com/web/treeview/api.html)

Проблема заключается в том, что фильтр применяется только к 1-й иерархии TreeView, поэтому, если текст-фильтр присутствует в дочернем, но не родительский, тогда ребенок не будет отображаться.

Пример:

  • Пункт 1
  • Пункт 2
    • Элемент xzy
    • Пункт abc

Если текст поиска будет "abc", ни один элемент не будет отображаться. Вместо этого я хотел бы получить следующий результат:

  • Пункт 2
    • Пункт abc

Кто-нибудь знает, как это сделать? Это код, который я использую:

   var tree_view_data = new kendo.data.HierarchicalDataSource({
        transport: {
            read: {
                url: "getall/items",
                dataType: "json"
            }
        },
        schema: {
            model: {
                children: "ChildItems"
            }
        }
    });
    //init tree view itself
    var $treeview = $("#div-treeview").kendoTreeView({
        dataSource: tree_view_data,
        dataTextField: [ "Text", "ChildrenText" ]
    });

    //allow filter of navigation tree
    var refreshTree = function () {
        tree_view_data.filter({
            field: "Text", //if I would use "ChildrenText" here nothing be displayed at all if filtertext is set
            operator: "contains",
            value: $("#tree-text-search").val()
        });
    };

    $("#tree-text-search").change(refreshTree).keyup(refreshTree);

Ответы

Ответ 1

Обновление 2016-01-13: теперь есть тема справки, которая показывает как выполнить фильтрацию TreeView на основе пользователя строка.

Вам нужно вручную фильтровать дочерние DataSources, чтобы отображались только необходимые узлы. Наличие разных dataTextField для разных уровней затрудняет понимание, поэтому этот код использует только поле text. Кроме того, поскольку эта фильтрация выполняется на стороне клиента, предполагается, что вы загрузили все узлы.

var treeview = $("#treeview").data("kendoTreeView"),
    item = treeview.findByText("Item 1.3"), // find the node that will be shown
    dataItem = treeview.dataItem(item),
    nodeText = dataItem.text;

// loop through the parents of the given node, filtering them to only one item
while (dataItem.parentNode()) {
    dataItem = dataItem.parentNode();
    dataItem.children.filter({ field: "text", operator: "contains", value: nodeText });
    nodeText = dataItem.text;
}

treeview.dataSource.filter({ field: "text", operator: "contains", value: nodeText });

Ответ 2

Я нашел способ сделать это только с помощью селекторов jQuery, чтобы скрыть и показать необходимые дочерние узлы.

Прежде всего, когда вы создаете свое древовидное представление, добавьте этот параметр в свои параметры:

loadOnDemand: false

Таким образом дерево будет отображать все HTML файлы дочерних узлов перед запросом, что позволит вам использовать jQuery для навигации.

Вот код jQuery, который у меня работает, который фильтрует нулевые узлы, которые не совпадают, открывает группу узлов, которые соответствуют, и показывает их.

$("#searchTextInputField").keyup(function () {

        var filterText = $("#searchTextInputField").val();

        if(filterText !== "") {   
            $("#myTree .k-group .k-group .k-in").closest("li").hide();
            $("#myTree .k-group .k-group .k-in:contains(" + filterText + ")").each(function() {
                $(this).closest("ul").show();
                $(this).closest("li").show();
            });
        } else {
            $("#myTree .k-group").find("ul").hide();
            $("#myTree .k-group").find("li").show();
        }
    });

Ответ 3

Для более чем 4 уровней пересекайте всех родителей типа UL и LI и show show().

$("#filterText").keyup(function (e) {
    var filterText = $(this).val();

    if (filterText !== "") {
        $("#treeview-standards .k-group .k-group .k-in").closest("li").hide();
        $("#treeview-standards .k-group .k-group .k-in:contains(" + filterText + ")").each(function () {
            $(this).parents("ul, li").each(function () {
                $(this).show();
            });
        });
    } else {
        $("#treeview-standards .k-group").find("ul").hide();
        $("#treeview-standards .k-group").find("li").show();
    }
});

Ответ 4

Прежде всего. KendoTreeView - это очень низкий уровень управления по сравнению с Teleriks RadDropDownTree из ASP.NET http://www.telerik.com/help/aspnet-ajax/dropdowntree-overview.html (я имею в виду js, конечно!) Должно быть, это нужно для jquery/kendo... необходимо было улучшить этот фильтр, поэтому если вы предпочитаете правильную фильтрацию на dataitem вместо "findByText", это делает:

.1) находит все данные .2) проверяет ваши условия (здесь строчные буквы содержат значение/текст) .3) флаг, флаг родителей .4) очистить, удалить узлы, оставшиеся в дереве родителями

that.nodeFilter = { logic: "or", filters: [] };
that.nodeFilter.filters.push({ field: "hidden", operator: "eq", value: false });
tree.element.find(".k-in").each(function () {
    var dItem = tree.dataItem($(this).closest("li"));
    dItem.hidden = false;
    if (dItem[that.options.dataValueField].toLowerCase().indexOf(searchTerm) != -1 ||
        dItem[that.options.dataTextField].toLowerCase().indexOf(searchTerm) != -1) {
        that.nodeFilter.filters.push({ field: that.options.dataValueField, operator: "eq", value: dItem[that.options.dataValueField] })
        while (dItem.parentNode()) {
            dItem = dItem.parentNode();
            dItem.hidden = false;
            that.nodeFilter.filters.push({ field: that.options.dataValueField, operator: "eq", value: dItem[that.options.dataValueField] })
        }
    } else {
        dItem.hidden = true;
    }
});
tree.dataSource.filter(that.nodeFilter);
tree.element.find(".k-in").each(function () {
    var node = $(this).closest("li");
    var dataItem = tree.dataItem(node);
    if (dataItem.hidden) {
        tree.remove(node);
    }
});

Ответ 5

Эта версия ищет все дерево, нечувствительна к регистру и скрывает узлы, которые не содержат поисковый запрос (jQuery 1.8 +).

$("#search").keyup(function (e) {
        var query = $(this).val();

        if (query !== "") {
            $("#tree-view .k-in").closest("li").hide();
            $("#tree-view .k-item .k-in:Contains(" + query + ")").each(function () {
                $(this).parents("ul, li").each(function () {
                    $(this).show();
                });
            });
        } else {
            $("#tree-view .k-group").find("ul").hide();
            $("#tree-view .k-group").find("li").show();
        }
    });

jQuery.expr[":"].Contains = jQuery.expr.createPseudo(function (arg) {
    return function (elem) {
        return jQuery(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
    };
});

Ответ 6

Если я хорошо прочитал вопрос, это касается фильтрации данных в представлении, а не самого дерева. Это можно сделать путем рекурсии.

Пример рекурсии, который работает:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>Kendo UI Snippet</title>

    <link rel="stylesheet" href="#" onclick="location.href='https://kendo.cdn.telerik.com/2018.1.117/styles/kendo.common.min.css'; return false;"/>
    <link rel="stylesheet" href="#" onclick="location.href='https://kendo.cdn.telerik.com/2018.1.117/styles/kendo.rtl.min.css'; return false;"/>
    <link rel="stylesheet" href="#" onclick="location.href='https://kendo.cdn.telerik.com/2018.1.117/styles/kendo.silver.min.css'; return false;"/>
    <link rel="stylesheet" href="#" onclick="location.href='https://kendo.cdn.telerik.com/2018.1.117/styles/kendo.mobile.all.min.css'; return false;"/>

    <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
    <script src="https://kendo.cdn.telerik.com/2018.1.117/js/kendo.all.min.js"></script>
</head>
<body>
  <div class="demo-section k-content">
    <div id="treeview1"></div>
    <div id="showit"></div>
    <div id="treeview2"></div>
  </div>
<script>
    //
    // Define hierarchical data source
    //
    var mydata = new kendo.data.HierarchicalDataSource({ 
      name: "Food", items: [
      { name: "Meat", items:
        [
          { name: "Pork" },
          { name: "Beef" }
        ]
      },
      { name: "Vegetables", items:
        [
          { name: "Pepper" }          
        ]
      }
      ]
    });

    //
    // When debugging
    //    
    var debug=false;
  
    //
    // Find and return Item when found.
    //
    function FindByName(items, myName)
    {
      //Query definition
      var query = kendo.data.Query.process(items, {
              filter: {
                logic: "or",
                filters: [{
                  field: "name",
                  value: myName,
                  operator: "eq"
                }]
              }
            });
      
       if (debug) $("#showit").html($("#showit").html()+"  found:" + JSON.stringify(query.data));
      
       //
       // return Item when found.
       //
       if (query.data != "")       
         return query.data; //ready
       else
       {
         //
         // if sub-items, search further
         //
         for (let i=0; i<items.length; i++)            
         {
           if (debug) $("#showit").html($("#showit").html()+"  test:" + JSON.stringify(items[i]));
           if (items[i].items!=null)
           {           
             if (debug) $("#showit").html($("#showit").html()+"  search sub....");
             var r = FindByName(items[i].items, myName);
             if (r!=null) return r; //ready, else continue searching further
           };
         }
       }
      if (debug) $("#showit").html($("#showit").html()+"  not found.");
      return null; //nothing found.
    }
  
    //
    // print the input
    //
    $("#showit").html($("#showit").html()+"  Food:" + JSON.stringify(mydata.options.items));
    //
    // print the result
    //
  	var ret=FindByName(mydata.options.items,"Beef");
    $("#showit").html($("#showit").html()+"<p>  Beef:" + JSON.stringify(ret));
    
    $("#treeview1").kendoTreeView({
      dataSource: mydata.options.items,
      dataTextField: ["name"]
    });

    ret=FindByName(mydata.options.items,"Meat");
    $("#showit").html($("#showit").html()+"<p>  Meat:" + JSON.stringify(ret));
    ret=FindByName(mydata.options.items,"Pepper");
    $("#showit").html($("#showit").html()+"<p>  Pepper:" + JSON.stringify(ret));
    ret=FindByName(mydata.options.items,"Vegetables");
    $("#showit").html($("#showit").html()+"<p>  Vegetables:" + JSON.stringify(ret));
    //
    // Example: bind return value [ret] to treeview.
    //
    $("#treeview2").kendoTreeView({
      dataSource: ret,
      dataTextField: ["name"]
    });
</script>
</body>
</html>