KendoUI фильтр 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);

6 ответов

Решение

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

Необходимо вручную отфильтровать дочерние источники данных, чтобы отображались только необходимые узлы. Имея разные dataTextField s для разных уровней затрудняет понимание, поэтому этот код использует 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 });

Я нашел способ сделать это, просто используя селекторы 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();
        }
    });

Для более чем 4-х уровней переберите всех родителей типа UL и LI и вызовите 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();
    }
});

Эта версия выполняет поиск по всему дереву, нечувствительна к регистру и скрывает узлы, которые не содержат поисковый запрос (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;
    };
});

Прежде всего. 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);
    }
});

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

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

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

    <link rel="stylesheet" href="https://kendo.cdn.telerik.com/2018.1.117/styles/kendo.common.min.css"/>
    <link rel="stylesheet" href="https://kendo.cdn.telerik.com/2018.1.117/styles/kendo.rtl.min.css"/>
    <link rel="stylesheet" href="https://kendo.cdn.telerik.com/2018.1.117/styles/kendo.silver.min.css"/>
    <link rel="stylesheet" href="https://kendo.cdn.telerik.com/2018.1.117/styles/kendo.mobile.all.min.css"/>

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

Другие вопросы по тегам