【问题标题】:Kendo TreeView Search with HighlightKendo TreeView Search with Highlight
【发布时间】:2014-09-02 20:31:02
【问题描述】:

我有一个带有 spriteclass 的 KendoTreeview。我想用我的搜索词突出显示节点(根节点和子节点)。我已经实现了搜索功能。但是当我搜索它时的问题是突出显示节点中的术语,但在第一次搜索后缺少节点中的 SpriteClass。有什么想法吗?

jsFiddle code

$('#search-term').on('keyup', function () {
    $('span.k-in > span.highlight').each(function () {
        $(this).parent().text($(this).parent().text());
    });

    // ignore if no search term
    if ($.trim($(this).val()) == '') {
        return;
    }

    var term = this.value.toUpperCase();
    var tlen = term.length;

    $('#treeview-sprites span.k-in').each(function (index) {
        var text = $(this).text();
        var html = '';
        var q = 0;
        while ((p = text.toUpperCase().indexOf(term, q)) >= 0) {
            html += text.substring(q, p) + '<span class="highlight">' + text.substr(p, tlen) + '</span>';
            q = p + tlen;
        }

        if (q > 0) {
            html += text.substring(q);
            $(this).html(html);

            $(this).parentsUntil('.k-treeview').filter('.k-item').each(

            function (index, element) {
                $('#treeview-sprites').data('kendoTreeView').expand($(this));
                $(this).data('search-term', term);
            });
        }
    });

$("#treeview-sprites").kendoTreeView({
    dataSource: [{
        text: "My Documents",
        expanded: true,
        spriteCssClass: "rootfolder",
        items: [{
            text: "Kendo UI Project",
            expanded: true,
            spriteCssClass: "folder",
            items: [{
                text: "about.html",
                spriteCssClass: "html"
            }, {
                text: "index.html",
                spriteCssClass: "html"
            }, {
                text: "logo.png",
                spriteCssClass: "image"
            }]
        }, {
            text: "New Web Site",
            expanded: true,
            spriteCssClass: "folder",
            items: [{
                text: "mockup.jpg",
                spriteCssClass: "image"
            }, {
                text: "Research.pdf",
                spriteCssClass: "pdf"
            }, ]
        }, {
            text: "Reports",
            expanded: true,
            spriteCssClass: "folder",
            items: [{
                text: "February.pdf",
                spriteCssClass: "pdf"
            }, {
                text: "March.pdf",
                spriteCssClass: "pdf"
            }, {
                text: "April.pdf",
                spriteCssClass: "pdf"
            }]
        }]
    }]
})

;

【问题讨论】:

    标签: javascript jquery kendo-ui kendo-treeview


    【解决方案1】:

    Kendo 的树形视图小部件不喜欢它的 HTML,因此我建议改为修改数据源(这将要求 DS 中的所有项目都使用 encoded 选项)。

    在 keyup 处理程序中,每当您搜索以清除突出显示时,您都会重置 DS,然后您设置模型的 text 属性而不是直接替换元素的 HTML:

    $('#search-term').on('keyup', function () {
        var treeView = $("#treeview-sprites").getKendoTreeView();
        treeView.dataSource.data(pristine);
    
        // ignore if no search term
        if ($.trim($(this).val()) == '') {
            return;
        }
    
        var term = this.value.toUpperCase();
        var tlen = term.length;
    
        $('#treeview-sprites span.k-in').each(function (index) {
            var text = $(this).text();
            var html = '';
            var q = 0;
            while ((p = text.toUpperCase().indexOf(term, q)) >= 0) {
                html += text.substring(q, p) + '<span class="highlight">' + text.substr(p, tlen) + '</span>';
                q = p + tlen;
            }
    
            if (q > 0) {
                html += text.substring(q);
    
                var dataItem = treeView.dataItem($(this));
                dataItem.set("text", html);
    
                $(this).parentsUntil('.k-treeview').filter('.k-item').each(
    
                function (index, element) {
                    $('#treeview-sprites').data('kendoTreeView').expand($(this));
                    $(this).data('search-term', term);
                });
            }
        });
    
        $('#treeview-sprites .k-item').each(function () {
            if ($(this).data('search-term') != term) {
                $('#treeview-sprites').data('kendoTreeView').collapse($(this));
            }
        });
    });
    

    树定义需要encoded 选项才能工作:

    var pristine = [{
        encoded: false,
        text: "Kendo UI Project",
        expanded: true,
        spriteCssClass: "folder",
        items: [{
            encoded: false,
            text: "about.html",
            spriteCssClass: "html"
        }, {
            encoded: false,
            text: "index.html",
            spriteCssClass: "html"
        }, {
            encoded: false,
            text: "logo.png",
            spriteCssClass: "image"
        }]
    }, {
        encoded: false,
        text: "New Web Site",
        expanded: true,
        spriteCssClass: "folder",
        items: [{
            encoded: false,
            text: "mockup.jpg",
            spriteCssClass: "image"
        }, {
            encoded: false,
            text: "Research.pdf",
            spriteCssClass: "pdf"
        }, ]
    }, {
        encoded: false,
        text: "Reports",
        expanded: true,
        spriteCssClass: "folder",
        items: [{
            encoded: false,
            text: "February.pdf",
            spriteCssClass: "pdf"
        }, {
            encoded: false,
            text: "March.pdf",
            spriteCssClass: "pdf"
        }, {
            encoded: false,
            text: "April.pdf",
            spriteCssClass: "pdf"
        }]
    }];
    
    $("#treeview-sprites").kendoTreeView({
        dataSource: [{
            text: "My Documents",
            expanded: true,
            spriteCssClass: "rootfolder",
            items: pristine
        }]
    });
    

    (demo)

    【讨论】:

      【解决方案2】:

      干得好伙计们,正是我需要的!

      使用您的代码,我做了一个小调整(实际上只添加了两行 jquery 过滤),因此现在在搜索关键字时,树视图仅显示包含突出显示文本的分支。十分简单! :)

      如果其他分支不包含高亮显示的文本,则它们将被隐藏。就这么简单。

      这意味着我们现在有了类似 VisualStudio 的树形视图搜索(请参阅 Visual Studio 解决方案资源管理器搜索和过滤器:http://goo.gl/qr7yVb)。

      这是我在 jsfiddle 上的代码和演示:http://jsfiddle.net/ComboFusion/d0qespaz/2/

      HTML:

      <input id="treeViewSearchInput"></input>
      <ul id="treeview">
          <li data-expanded="true">My Web Site
              <ul>
                  <li data-expanded="true">images
                      <ul>
                          <li>logo.png</li>
                          <li>body-back.png</li>
                          <li>my-photo.jpg</li>
                      </ul>
                  </li>
                  <li data-expanded="true">resources
                      <ul>
                          <li data-expanded="true">pdf
                              <ul>
                                  <li>brochure.pdf</li>
                                  <li>prices.pdf</li>
                              </ul>
                          </li>
                          <li>zip</li>
                      </ul>
                  </li>
                  <li>about.html</li>
                  <li>contacts.html</li>
                  <li>index.html</li>
                  <li>portfolio.html</li>
              </ul>
          </li>
          <li>Another Root</li>
      </ul>
      

      CSS

      span.k-in > span.highlight {
          background: #7EA700;
          color: #ffffff;
          border: 1px solid green;
          padding: 1px;
      }
      

      JAVASCRIPT

      function InitSearch(treeViewId, searchInputId) {
      
          var tv = $(treeViewId).data('kendoTreeView');
      
          $(searchInputId).on('keyup', function () {
      
              $(treeViewId + ' li.k-item').show();
      
              $('span.k-in > span.highlight').each(function () {
                  $(this).parent().text($(this).parent().text());
              });
      
              // ignore if no search term
              if ($.trim($(this).val()) === '') {
                  return;
              }
      
              var term = this.value.toUpperCase();
              var tlen = term.length;
      
              $(treeViewId + ' span.k-in').each(function (index) {
                  var text = $(this).text();
                  var html = '';
                  var q = 0;
                  var p;
      
                  while ((p = text.toUpperCase().indexOf(term, q)) >= 0) {
                      html += text.substring(q, p) + '<span class="highlight">' + text.substr(p, tlen) + '</span>';
                      q = p + tlen;
                  }
      
                  if (q > 0) {
                      html += text.substring(q);
                      $(this).html(html);
      
                      $(this).parentsUntil('.k-treeview').filter('.k-item').each(function (index, element) {
                          tv.expand($(this));
                          $(this).data('SearchTerm', term);
                      });
                  }
              });
      
              $(treeViewId + ' li.k-item:not(:has(".highlight"))').hide();
      
              $(treeViewId + ' li.k-item').expand(".k-item");
          });
      }
      
      var $tv = $("#treeview").kendoTreeView();
      
      InitSearch("#treeview", "#treeViewSearchInput");
      

      【讨论】:

        【解决方案3】:

        我的另一个调整:)

        我所做的是更改高亮代码以保留节点 html 中可能存在的任何其他内容(例如 sprite span)。

        我还将它实现为 TreeView 周围的 TypeScript 类包装器。

        如果您不想要 TypeScript 的东西,只需将代码复制出来,它应该可以正常工作:)

        export class SearchableTreeView {
            TreeView: kendo.ui.TreeView;
            emphasisClass: string;
        
            constructor(treeView: kendo.ui.TreeView) {
                this.TreeView = treeView;
                this.emphasisClass = "bg-warning";
            }
        
            search(term: string): void {
                var treeElement: JQuery = this.TreeView.element;
                var tv: kendo.ui.TreeView = this.TreeView;
                var emphClass = this.emphasisClass;
        
                this.resetHighlights();
        
                // ignore if no search term
                if ($.trim(term) === '') { return; }
        
                var term = term.toUpperCase();
                var tlen = term.length;
        
                $('span.k-in', treeElement).each(function (index) {
                    // find all corresponding nodes
                    var node = $(this);
                    var htmlContent = node.html();
                    var text = node.text();
        
                    var searchPosition = text.toUpperCase().indexOf(term);
                    if (searchPosition === -1) {
                        // continue
                        return true;
                    }
        
                    var generatedHtml = '<span class="highlight-container">' + text.substr(0, searchPosition) + '<span class="' + emphClass + '">' + text.substr(searchPosition, tlen) + '</span>' + text.substr(searchPosition + tlen) + '</span>';
        
                    htmlContent = htmlContent.replace(text, generatedHtml);
                    node.html(htmlContent);
        
                    node.parentsUntil('.k-treeview').filter('.k-item').each(
                        function (index, element) {
                            tv.expand($(this));
                            $(this).data('search-term', term);
                        }
                    );
        
                });
        
                $('.k-item', treeElement).each(function () {
                    if ($(this).data('search-term') != term) {
                        tv.collapse($(this));
                    }
                });
            }
        
            resetHighlights(): void {
                this.TreeView.element.find("span.k-in:has('." + this.emphasisClass + "')")
                    .each(function () {
                        var node = $(this);
                        var text = node.text();
                        $(".highlight-container", node).remove();
                        node.append(text);
                    });
            }
        }
        

        【讨论】:

          【解决方案4】:
             $("#textBox").on("input", function () {
          
              var query = this.value.toLowerCase();
              var dataSource = $("#Treeview").data("kendoTreeView").dataSource;
          
              filter(dataSource, query);
             });
          
          
            function filter(dataSource, query) {
                  var uidData = [];
                  var data = dataSource instanceof kendo.data.DataSource && dataSource.data();
                  for (var i = 0; i < data.length; i++) {
                      var item = data[i];
                      var text = item.text.toLowerCase();
                      var isChecked = item.checked;
                      var itemVisible =
                          query === true 
                          || query === "" 
                          || text.indexOf(query) >= 0; 
          
                      uidData.push({ UID: item.uid, Visible: itemVisible });
          
                  }
          
                  if (query != "") {
                      $.each(uidData, function (index, datavalue) {
                          if (datavalue.Visible) {
                              $("li[data-uid='" + datavalue.UID + "']").addClass("highlight");
                          }
                          else {
                              $("li[data-uid='" + datavalue.UID + "']").removeClass("highlight");
                          }
          
                      });
                  }
                  else {
                      $.each(uidData, function (index, datavalue) {
                          $("li[data-uid='" + datavalue.UID + "']").removeClass("highlight");
          
                      });
                  }
              }
          

          CSS:

          .highlight {
              background:#0fa1ba;
              color:white;
          }
          

          【讨论】:

            【解决方案5】:

            对于 Angular 2+,您需要为此功能创建一个管道。

            import { Pipe, PipeTransform } from '@angular/core';
            import { DomSanitizer } from '@angular/platform-browser';
            import { NGXLogger } from 'ngx-logger';
            
            @Pipe({
                name: 'highlight'
            })
            
            export class TypeaheadHighlight implements PipeTransform {
                constructor(private readonly _sanitizer: DomSanitizer, private readonly logger: NGXLogger) { }
                transform(matchItem: any, query: any): string {
                    let matchedItem: any;
                    if (matchItem) {
                        matchedItem = matchItem.toString();
                    }
                    if (this.containsHtml(matchedItem)) {
                        this.logger.warn('Unsafe use of typeahead please use ngSanitize');
                    }
                    matchedItem = query ? ('' + matchedItem).replace(new RegExp(this.escapeRegexp(query), 'gi'), '<strong>$&</strong>') : matchedItem; // Replaces the capture string with a the same string inside of a "strong" tag
            
                    if (!this._sanitizer) {
                        matchedItem = this._sanitizer.bypassSecurityTrustHtml(matchedItem);
                    }
            
                    return matchedItem;
                }
            
                escapeRegexp = (queryToEscape) => queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
            
                containsHtml = (matchItem) => /<.*>/g.test(matchItem);
            
            } 
            

            在 html 模板中使用这个管道......

                        <input name="searchTerm" type="text" [(ngModel)]="searchTerm" (keyup)='onkeyup(searchTerm)'
                         />
                    </div>
            
                    <div style="height: 70vh;overflow: auto">
                        <kendo-treeview style="margin-top: 50px" id="availableColumns" [nodes]="availableColumns"
                            textField="displayName" kendoTreeViewExpandable kendoTreeViewFlatDataBinding idField="id"
                            parentIdField="parentId">
                            <ng-template kendoTreeViewNodeTemplate let-dataItem>
                                <span [tooltip]="dataItem.columnDescription"
                                    [innerHtml]="dataItem.displayName | highlight:searchTerm "></span>
                            </ng-template>
                        </kendo-treeview>
                    </div> 
            

            【讨论】:

              猜你喜欢
              • 2017-12-20
              • 1970-01-01
              • 2015-03-30
              • 2012-10-28
              • 1970-01-01
              • 2023-03-15
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多