光滑网格树视图搜索
Slickgrid Treeview Search
我目前正在使用slikgrid实现一个树视图。
我的代码基本上是基于这个例子。
我想做的是得到一个搜索过滤器,类似于一个在例子中,但它的工作在分支以及父母。例如,如果树看起来像这样:
-Parent 1
-branch 1
-sub_branch 1
-branch 2
-Parent 2
-branch 1
-branch 2
然后搜索数字'1'它应该显示如下:
-Parent 1
-branch 1
-sub_branch 1
-branch 2
-Parent 2
-branch 1
而不是:
-Parent 1
对不起,我没有任何代码要展示,我没有得到任何地方。什么好主意吗?由于
更新:
我不得不改进我在一年前的这个星期写的代码,经过大量的测试,这就是我最终得到的。这种方法比旧方法快得多,而且我的意思是快得多!在节点深度为5个节点和5100行的情况下,该数据准备大约需要1.3s,但是如果您不需要不区分大小写的搜索,删除toLowerCase将使时间减半,大约为600ms。当准备好搜索字符串时,搜索是即时的。
这是来自我们的setData函数,我们准备数据
var self = this,
searchProperty = "name";
//if it's a tree grid, we need to manipulate the data for us to search it
if (self.options.treeGrid) {
//createing index prop for faster get
createParentIndex(items);
for (var i = 0; i < items.length; i++) {
items[i]._searchArr = [items[i][searchProperty]];
var item = items[i];
if (item.parent != null) {
var parent = items[item.parentIdx];
while (parent) {
parent._searchArr.push.apply(
parent._searchArr, uniq_fast(item._searchArr)
);
item = parent;
parent = items[item.parentIdx];
}
}
}
//constructing strings to search
//for case insensitive (.toLowerCase()) this loop is twice as slow (1152ms instead of 560ms for 5100rows) .toLowerCase();
for (var i = 0; i < items.length; i++) {
items[i]._search = items[i]._searchArr.join("/").toLowerCase();
items[i]._searchArr = null;
}
//now all we need to do in our filter is to check indexOf _search property
}
在上面的代码中,我使用了一些函数。第一个创建了两个属性,一个用于它在数组中的位置,第二个parentIdx用于parents索引。我不确定这是否真的提高了性能,但是它消除了在setData函数中嵌套循环的需要。这里真正起作用的是uniq_fast,它接受一个数组并删除其中的所有重复项。该方法是这个答案中的众多函数之一。
function createParentIndex(items) {
for (var i = 0; i < items.length; i++) {
items[i].idx = i; //own index
if (items[i].parent != null) {
for (var j = 0; j < items.length; j++) {
if (items[i].parent === items[j].id) {
items[i].parentIdx = j; //parents index
break;
}
}
}
}
}
function uniq_fast(a) {
var seen = {};
var out = [];
var len = a.length;
var j = 0;
for (var i = 0; i < len; i++) {
var item = a[i];
if (seen[item] !== 1) {
seen[item] = 1;
out[j++] = item;
}
}
return out;
}
现在,所有这些数据的准备,我们的过滤器函数实际上变得非常小,易于处理。对每个项目调用过滤器函数,因为现在每个项目上都有_search属性,所以我们只需检查它。如果没有应用过滤器,我们需要确保不显示封闭节点
function treeFilter(item, args) {
var columnFilters = args.columnFilters;
var propCount = 0;
for (var columnId in columnFilters) {
if (columnId !== undefined && columnFilters[columnId] !== "") {
propCount++;
if (item._search === undefined || item._search.indexOf(columnFilters[columnId]) === -1) {
return false;
} else {
item._collapsed = false;
}
}
}
if (propCount === 0) {
if (item.parent != null) {
var dataView = args.grid.getData();
var parent = dataView.getItemById(item.parent);
while (parent) {
if (parent._collapsed) {
return false;
}
parent = dataView.getItemById(parent.parent);
}
}
}
return true;
}
所以,这个问题很久以前就被问到了,但是如果有人正在寻找这个问题的答案,请使用上面的代码。它很快,但是对代码的任何改进都是值得赞赏的!END OF EDIT
旧答案(这是非常慢的):
首先,您必须创建一个与dataView一起使用的筛选函数。只要您键入一些内容,dataView就会调用您的函数。将对dataView中的每一行调用该函数,并将该行作为项参数传递。返回false表示该行应该隐藏,返回true表示该行可见。查看Tree示例,过滤器函数如下所示
function myFilter(item, args) {
if (item["percentComplete"] < percentCompleteThreshold) {
return false;
}
if (searchString != "" && item["title"].indexOf(searchString) == -1) {
return false;
}
if (item.parent != null) {
var parent = data[item.parent];
while (parent) {
if (parent._collapsed || (parent["percentComplete"] < percentCompleteThreshold) || (searchString != "" && parent["title"].indexOf(searchString) == -1)) {
return false;
}
parent = data[parent.parent];
}
}
return true;
}
在我第一次尝试这样做时,我试图操纵父元素,使它不应该被隐藏。问题是,我不知道如何取消隐藏它,问题也是,你不知道在哪个顺序行将被过滤(如果父行是最后被过滤,父属性是null)
我放弃了这个想法,并尝试处理传递到方法中的项,因为这就是它的意图。当使用基本的父/子树结构时,可以使用递归。
我的解决方案首先,创建一个保存所有过滤并返回true或false的函数。我使用固定的标题行作为快速过滤器的基础,然后添加我自己的规则。这是我的realFilter函数的简化版本,所以你可能需要稍微调整一下。
function realFilter(item, args) {
var columnFilters = args.columnFilters;
var grid = args.grid;
var returnValue = false;
for (var columnId in columnFilters) {
if (columnId !== undefined && columnFilters[columnId] !== "") {
returnValue = true;
var c = grid.getColumns()[grid.getColumnIndex(columnId)];
if (item[c.field].toString().toLowerCase().indexOf(
columnFilters[columnId].toString().toLowerCase()) == -1) { //if true, don't show this post
returnValue = false;
}
}
}
return returnValue;
}
其次,是使用递归函数的时候了。如果你不熟悉它们的工作原理,这是一个棘手的部分。
//returns true if a child was found that passed the realFilter
function checkParentForChildren(parent, allItems, args) {
var foundChild = false;
for (var i = 0; i < allItems.length; i++) {
if (allItems[i].parent == parent.id) {
if (realFilter(allItems[i], args) == false && foundChild == false) //if the child do not pass realFilter && no child have been found yet for this row
foundChild = checkParentForChildren(allItems[i], allItems, args);
else
return true;
}
}
return foundChild;
}
最后,我们实现了原来的滤波函数。这是由slickgrid调用的函数,应该注册到dataView
//registration of the filter
dataView.setFilter(filter);
//the base filter function
function filter(item, args) {
var allRows = args.grid.getData().getItems();
var columnFilters = args.columnFilters;
var grid = args.grid;
var checkForChildren = false;
for (var i = 0; i < allRows.length; i++) {
if (allRows[i].parent == item.id) {
checkForChildren = true;
break;
}
}
for (var columnId in columnFilters) {
if (columnId !== undefined && columnFilters[columnId] !== "") {
var c = grid.getColumns()[grid.getColumnIndex(columnId)];
var searchString = columnFilters[columnId].toLowerCase().trim();
if (c != undefined) {
if (item[c.field] == null || item[c.field] == undefined) {
return false;
}
else {
var returnValue = true;
if (checkForChildren) {
returnValue = checkParentForChildren(item, allRows, args);
if(!returnValue)
returnValue = realFilter(item, args);
}
else
returnValue = realFilter(item, args);
if (item.parent != null && returnValue == true) {
var dataViewData = args.grid.getData().getItems();
var parent = dataViewData[item.parent];
while (parent) {
if (parent._collapsed) {
parent._collapsed = false;
}
parent = dataViewData[parent.parent];
}
}
return returnValue;
}
}
}
}
if (item.parent != null) {
var dataViewData = args.grid.getData().getItems();
var parent = dataViewData[item.parent];
while (parent) {
if (parent._collapsed) {
return false;
}
parent = dataViewData[parent.parent];
}
}
return true;
}
我目前正在处理这个问题,所以我还没有真正费心去改进代码。据我所知,它正在工作,但你可能不得不调整一些东西在过滤器和realFilter让它像你期望的那样工作。我今天写了这篇文章,所以它的测试时间不会超过开发阶段。
注意:如果您想使用另一个输入为您的搜索,您可以只使用$.keyup()字段,然后将数据传递给标题过滤器。通过这种方式,您可以获得使用列级过滤器的所有功能,即使在这种特殊情况下您不想使用它们。
我个人使用分组的例子,我也帮助使它多列(嵌套)分组,它做的正是你正在寻找的…所以不要用你说的那个,我认为它主要是用来缩进的,你应该用这个交互式分组和聚合。
示例不包括搜索,但很容易添加它,就像在我的项目。是的,父母群体永远不会消失。在多列分组的例子中,选择50k行,然后点击"按持续时间分组,然后按努力驱动,然后按百分比分组,你会看到一个漂亮的3列分组:)复制它,添加搜索栏,应该可以了
编辑我增加了对过滤树数据的支持,最近还增加了对聚合器功能的树总数的支持。您可以看到这些slikgrid - universal示例(我创建的)
- 示例5
- 例子6
还请注意,在我的其他项目
中可以使用完全相同的功能。- Angular-Slickgrid
- Aurelia-Slickgrid
- Slickgrid-React
- Ajax Live搜索发布到Laravel视图
- 从json文件输出多个屏幕截图(例如itunes搜索api)
- 如何使用搜索筛选器初始化列表视图
- 主干:如何操作与视图关联的图元之外的图元
- 谷歌地图API:热图&搜索-无法合并到单个映射中
- 照片滑动 - 无图库视图 - 没有导航按钮
- jQuery 图层选择器类型插件或可自定义的列表视图插件
- Javascript树视图可视化工具,用于说“调用图”
- 角度 NVD3 指令饼图 nodata 不刷新视图
- jQuery - 搜索结果视图 - List & Grid
- Paperjs 栅格化具有视图边界的活动图层
- 角度如何在搜索和结果视图之间切换并传递数据
- 开放图层:从 WFS 图层搜索
- 如何将自动完成搜索框重定向到显示视图
- 搜索在网格视图上不起作用
- 将Android网络视图渲染为位图,html5 javascript,回调问题
- 在类别筛选视图中搜索
- jQuery mobile折叠列表视图,搜索不起作用
- HTML视图在搜索(ajax)更新期间丢失状态
- 使用flot图表创建时间序列图,该图表具有选定时间格式的选项视图图