简体   繁体   English

如何覆盖JQGrid中的默认搜索功能

[英]How do I override the default search functionality in JQGrid

I have a JQGrid setup with the search bar appearing at the top. 我有一个JQGrid设置,搜索栏出现在顶部。 For text fields I want the search bar to function normally. 对于文本字段,我希望搜索栏正常运行。 The same in cases when I create a dropdown with a few exact-match options. 在我使用一些完全匹配选项创建下拉列表的情况下也是如此。 However, for date fields, or number ranges, I want to create a dropdown that will allow users to search by ranges. 但是,对于日期字段或数字范围,我想创建一个允许用户按范围搜索的下拉列表。 I assume that in these cases I need to override the existing search functionality for JQGrid and write my own search functions. 我假设在这些情况下我需要覆盖JQGrid的现有搜索功能并编写我自己的搜索功能。

I assume this is done with the fn searchoption. 我假设这是通过fn searchoption完成的。 So far I've gotten as far as the below. 到目前为止,我已经达到了以下目标。 This creates the grid and search options exactly as I'd like. 这将完全按照我的意愿创建网格和搜索选项。 However, trying to make any search clears the entire grid, presumably because it doesn't know how to deal with the special date and range dropdowns. 但是,尝试进行任何搜索都会清除整个网格,大概是因为它不知道如何处理特殊日期和范围下拉列表。 I'd appreciate insight on how to continue. 我很欣赏有关如何继续的见解。 If this functionality already exists in JQGrid could you please tell me how to access it? 如果JQGrid中已存在此功能,请告诉我如何访问它?

As an aside, I want to keep all processing local. 顺便说一句,我想保持所有处理本地。 The primary advantage of something like JQGrid is eliminating the load from multiple database requests, and eliminating the latency and overhead imposed by so many HTTP connections. 像JQGrid这样的主要优点是消除了多个数据库请求的负载,并消除了这么多HTTP连接带来的延迟和开销。

<script>
    $("#grid1").jqGrid({
        datatype:       "local",
        height:         250,
        colNames:       ['CF Template', 'Error Date', 'Skey', 'Type', 'Summary'],
        colModel:       [

                                {   name: 'page_name',
                                    index: 'page_name',
                                    width: 400,
                                    sorttype: 'text',
                                    search:true,
                                    stype:'text'
                                }
                                , 
                                {   name: 'row_timestamp',
                                    index: 'row_timestamp',
                                    width: 100,
                                    sorttype: 'date',
                                    search:true,
                                    stype:'select',
                                    searchoptions: {
                                        value:{'0':'Any','2014-2-01_2014-2-28':'February','2014-3-01_2014-3-31':'March','2014-4-01_2014-4-30':'April'},
                                        dataEvents: [
                                            {
                                                type: 'change',
                                                fn: function(e) {
                                                    alert($('#gs_row_timestamp option:selected').val());
                                                    alert($('#gs_row_timestamp option:selected').text());
                                                    alert('4');
                                                }
                                            }
                                        ]
                                    }
                                }
                                , 
                                {   name: 'row_id',
                                    index: 'row_id',
                                    width: 100,
                                    sorttype: 'int',
                                    search:true,
                                    stype:'select',
                                    searchoptions: {
                                        value:{0:'Any',2:'0 - 12000000000',3:'12000000000 - 24000000000',4:'24000000000 - 36000000000',5:'36000000000 - 48000000000',6:'48000000000 - 60000000000'},
                                        dataEvents: [
                                            {
                                                type: 'change',
                                                fn: function(e) {
                                                    alert($('#gs_row_id option:selected').val());
                                                    alert($('#gs_row_id option:selected').text());
                                                    alert('2');
                                                }
                                            }
                                        ]
                                    }
                                }
                                , 
                                {   name: 'error_type',
                                    index: 'error_type',
                                    width: 100,
                                    sorttype: 'text',
                                    search:true,
                                    stype:'select',
                                    searchoptions: {
                                        value:{0:'Any',2:'Application',3:'Database',4:'Expression',5:'MissingInclude'},
                                        dataEvents: [
                                            {
                                                type: 'change',
                                                fn: function(e) {
                                                    alert($('#gs_error_type option:selected').val());
                                                    alert($('#gs_error_type option:selected').text());
                                                    alert('1');
                                                }
                                            }
                                        ]
                                    }
                                }
                                , 
                                {   name: 'error_summary',
                                    index: 'error_summary',
                                    width: 500,
                                    sorttype: 'text',
                                    search:true,
                                    stype:'text'
                                }

                        ],
        multiselect:    false,
        rowNum:         25,         // Number of rows shown per page; must also change down below
        pager:          '#pager1',  
        height:         250,        
        altRows:        true,                       // Allows for styling of alt rows
        altclass:       'altRowClass',              // Create striped rows
        viewrecords:    true,                       // Show recordcount in lower right corner
        ignoreCase:     true,                       // Case insensitive searches
        multiSort:      true,
    </script>

UPDATE UPDATE

It seems that using e.stopImmediatePropagation() works to prevent the grid from clearing, but I'm not sure how to control the search from there. 似乎使用e.stopImmediatePropagation()可以防止网格清除,但我不确定如何从那里控制搜索。 Instead of the fn should I be looking in the line that defines the search bar to set some special searching function? 我应该在定义搜索栏的行中查找设置一些特殊搜索功能而不是fn吗?

    $("#grid1").jqGrid('filterToolbar', {stringResult: true, searchOnEnter: false, defaultSearch : "cn"});

UPDATE UPDATE

It occurred to me that some sample data might be helpful. 我想到一些样本数据可能会有所帮助。 Here are a few records as they are being defined on the page. 以下是在页面上定义的一些记录。 They are loaded once on the same page as the JQGrid, then all searching and filtering should occur locally. 它们在与JQGrid相同的页面上加载一次,然后所有搜索和过滤都应在本地进行。

        var mydata = [

                {
                    page_name:  "C:\\inetpub\\wwwroot\\AppName\\AppFolder\\interface\\home.cfm"
                        , row_timestamp:    "2014-04-29 13:25:08.528"
                        , row_id:   "135200030"
                        , error_type:   "MissingInclude"
                        , error_summary:    "This is some sample text for example purposes.  Real data would be here."

                }
                , 
                {
                    page_name:  "C:\\inetpub\\wwwroot\\AppName\\AppFolder\\interface\\home.cfm"
                        , row_timestamp:    "2014-04-29 13:24:48.575"
                        , row_id:   "135200040"
                        , error_type:   "MissingInclude"
                        , error_summary:    "This is some sample text for example purposes.  Real data would be here."

                }
                , 
                {
                    page_name:  "C:\\inetpub\\wwwroot\\AppName\\AppFolder\\interface\\Report\\repot_file_1.cfm"
                        , row_timestamp:    "2014-04-25 08:46:04.428"
                        , row_id:   "135200050"
                        , error_type:   "Expression"
                        , error_summary:    "This is some sample text for example purposes.  Real data would be here."

                }
                , 
                {
                    page_name:  "C:\\inetpub\\wwwroot\\AppName\\AppFolder\\interface\\Report\\repot_file_1.cfm"
                        , row_timestamp:    "2014-04-25 08:46:03.944"
                        , row_id:   "135200060"
                        , error_type:   "Expression"
                        , error_summary:    "This is some sample text for example purposes.  Real data would be here."

                }
                , 
                {
                    page_name:  "C:\\inetpub\\wwwroot\\AppName\\AppFolder\\interface\\Test\\jqtest.cfm"
                        , row_timestamp:    "2014-04-16 10:10:14.729"
                        , row_id:   "135200070"
                        , error_type:   "Expression"
                        , error_summary:    "This is some sample text for example purposes.  Real data would be here."

                }
                , 
                {
                    page_name:  "C:\\inetpub\\wwwroot\\AppName\\AppFolder\\interface\\Common\\interface\\subFolder_1\\Activity\\loader_file_1.cfm"
                        , row_timestamp:    "2014-04-15 16:47:51.477"
                        , row_id:   "135200080"
                        , error_type:   "Database"
                        , error_summary:    "This is some sample text for example purposes.  Real data would be here."

                }
                , 
                {
                    page_name:  "C:\\inetpub\\wwwroot\\AppName\\AppFolder\\interface\\Common\\interface\\subFolder_1\\Blank\\loader_file_2.cfm"
                        , row_timestamp:    "2014-04-15 16:47:50.071"
                        , row_id:   "135200090"
                        , error_type:   "Database"
                        , error_summary:    "This is some sample text for example purposes.  Real data would be here."

                }
                , 
                {
                    page_name:  "C:\\inetpub\\wwwroot\\AppName\\AppFolder\\interface\\Common\\interface\\subFolder_1\\Activity\\loader_file_1.cfm"
                        , row_timestamp:    "2014-04-15 16:42:22.18"
                        , row_id:   "135300000"
                        , error_type:   "Database"
                        , error_summary:    "This is some sample text for example purposes.  Real data would be here."

                }
                , 
                {
                    page_name:  "C:\\inetpub\\wwwroot\\AppName\\AppFolder\\interface\\Common\\interface\\subFolder_1\\Blank\\loader_file_2.cfm"
                        , row_timestamp:    "2014-04-15 16:42:20.664"
                        , row_id:   "135300010"
                        , error_type:   "Database"
                        , error_summary:    "This is some sample text for example purposes.  Real data would be here."

                }
                , 
                {
                    page_name:  "C:\\inetpub\\wwwroot\\AppName\\AppFolder\\interface\\subFolder_12\\Activity\\action_page_1.cfm"
                        , row_timestamp:    "2014-04-08 11:53:38.01"
                        , row_id:   "135300020"
                        , error_type:   "Expression"
                        , error_summary:    "This is some sample text for example purposes.  Real data would be here."

                }
                , 
                {
                    page_name:  "C:\\inetpub\\wwwroot\\AppName\\AppFolder\\interface\\subFolder_12\\Activity\\action_page_1.cfm"
                        , row_timestamp:    "2014-04-08 11:28:23.948"
                        , row_id:   "135300030"
                        , error_type:   "Database"
                        , error_summary:    "This is some sample text for example purposes.  Real data would be here."

                }
                , 
                {
                    page_name:  "C:\\inetpub\\wwwroot\\AppName\\AppFolder\\interface\\subFolder_12\\Activity\\action_page_1.cfm"
                        , row_timestamp:    "2014-04-08 11:07:24.76"
                        , row_id:   "135300040"
                        , error_type:   "Database"
                        , error_summary:    "This is some sample text for example purposes.  Real data would be here."

                }
                , 
                {
                    page_name:  "C:\\inetpub\\wwwroot\\AppName\\AppFolder\\interface\\subFolder_12\\Activity\\action_page_1.cfm"
                        , row_timestamp:    "2014-04-08 10:30:13.026"
                        , row_id:   "135300050"
                        , error_type:   "Database"
                        , error_summary:    "This is some sample text for example purposes.  Real data would be here."

                }
                , 
                {
                    page_name:  "C:\\inetpub\\wwwroot\\AppName\\AppFolder\\interface\\Common\\CustomTag\\stored_proc.cfm"
                        , row_timestamp:    "2014-04-08 09:03:21.588"
                        , row_id:   "135300060"
                        , error_type:   "Database"
                        , error_summary:    "This is some sample text for example purposes.  Real data would be here."

                }
                , 
                {
                    page_name:  "C:\\inetpub\\wwwroot\\AppName\\AppFolder\\interface\\EdiErrorQueue\\INVN\\Frameset_1.cfm"
                        , row_timestamp:    "2014-02-19 09:52:43.078"
                        , row_id:   "135300070"
                        , error_type:   "Expression"
                        , error_summary:    "This is some sample text for example purposes.  Real data would be here."

                }
                , 
                {
                    page_name:  "C:\\inetpub\\wwwroot\\AppName\\AppFolder\\interface\\EdiErrorQueue\\INVN\\Frameset_1.cfm"
                        , row_timestamp:    "2014-02-19 09:46:10.906"
                        , row_id:   "135300080"
                        , error_type:   "Expression"
                        , error_summary:    "This is some sample text for example purposes.  Real data would be here."

                }

        ];
        for (var i = 0; i < mydata.length; i++)
            jQuery("#grid1").jqGrid('addRowData', i + 1, mydata[i]);
        jQuery("#grid1").setGridParam({ rowNum: 25 }).trigger("reloadGrid");

Problem 问题

Indeed, jqGrid does not let you define you own filtering function to apply when filtering local data. 实际上,jqGrid不允许您定义自己的过滤功能,以便在过滤本地数据时应用。 What you want to achieve is possible but far from straightforward. 您想要实现的目标是可能的,但远非直截了当。 One reason is that jqGrid relies on jLinq to perform the search. 一个原因是jqGrid依赖于jLinq来执行搜索。 But it does not simply call jLinq to do the search, the code of jLinq was copy-pasted into jqGrid code and called in the middle of the grid internals... Which makes it impossible to extend the search feature in a clean way. 但它并不是简单地调用jLinq进行搜索,将jLinq的代码复制粘贴到jqGrid代码中并在网格内部中间调用...这使得无法以干净的方式扩展搜索功能。

This is why you got stuck when trying to provide your own change event handler. 这就是为什么在尝试提供自己的更改事件处理程序时遇到困难的原因。 The default code of the handler is: 处理程序的默认代码是:

function(){
    triggerToolbar();
    return false;
}

And the triggerToolbar function is a "do everything" function that will reload the data, re-draw the complete grid will all the library machinery, and somewhere in the middle filter the data without any hook for you to intercept the search function. triggerToolbar函数是一个“do everything”函数,它将重新加载数据,重新绘制完整的网格将所有库机器,以及中间的某个地方过滤数据而不用任何钩子来拦截搜索功能。

From here, I can see three solutions: 从这里,我可以看到三个解决方案:

  • Request the feature to jqGrid developers 向jqGrid开发人员请求该功能
  • Modify the code of jqGrid. 修改jqGrid的代码。 When I had a look it seemed difficult to do so while making sure you are not breaking the library. 当我看到它时似乎很难这样做,同时确保你没有打破图书馆。
  • The hacker way: let believe jqGrid that the data comes from a server, and filter it yourself 黑客方式:让jqGrid相信数据来自服务器,并自行过滤

Solution

I will expand only on the third solution. 我将仅扩展第三个解决方案。 The idea is to use the fact that jqGrid uses jQuery to talk to the server and register an ajax proxy in jQuery. 我们的想法是使用jqGrid使用jQuery与服务器通信并在jQuery中注册ajax代理的事实。 This proxy will intercept all ajax calls, and return your local data filtered according to the query parameters sent by jqGrid. 此代理将拦截所有ajax调用,并根据jqGrid发送的查询参数返回过滤的本地数据。 This will execute all the jQuery machinery any time the filters are changed, but it works. 这将在任何时候更改过滤器时执行所有jQuery机制,但它可以工作。

1. Create the proxy 1.创建代理

The first step is to convert your current setting into one where jqGrid believes the data comes from a server. 第一步是将当前设置转换为jqGrid认为数据来自服务器的设置。 You do this with the function $.ajaxTransport ( documentation ), to which you provide a function that will be called before any ajax call. 您可以使用函数$.ajaxTransport文档 )执行此操作,您将在其中提供将在任何ajax调用之前调用的函数。 Based on the options, you can decide whether you want to provide your own object that will take care of the call, or let $.ajax() do its usual job. 根据选项,您可以决定是否要提供自己的对象来处理调用,或者让$.ajax()完成其通常的工作。 I based this decision on a known url, which we will give to jqGrid later. 我基于一个已知的url做出了这个决定,我们稍后会给jqGrid。 This can be anything, as long as it is NOT cross-domain (don't use the current URL like me if it may contain query parameters). 这可以是任何东西,只要它不是跨域的(如果它可能包含查询参数,请不要使用像我这样的当前URL)。 Here is the code: 这是代码:

var mydata = [ /* Your local data */ ];
var gridurl = window.location.href + "/mygrid";

$.ajaxTransport("json", function(options) {
  if(options.url.indexOf(gridurl) === 0) {
    return {
      send: function(headers, completeCallback) {
        setTimeout(function(){ //We still want the call to be asynchroneous
            completeCallback(200, "success", {json: mydata});
        }, 10);
      },
      abort: function() {
        //Do nothing
      }
    };
  }
});

And the updated jqGrid settings: 并更新了jqGrid设置:

$("#grid1").jqGrid({
    url:       gridurl,
    datatype:  "json",
    height:    250,
    colNames:  ['CF Template', 'Error Date', 'Skey', 'Type', 'Summary'],
    /* ... */
});

//No call to addRowData

2. Implement the filter 2.实施过滤器

Once you have done step 1, you should already be able to load and display the grid. 完成步骤1后,您应该已经能够加载并显示网格。 Now let's modify the proxy so that it filters the data according to the search parameters that jqGrid has put in the url. 现在让我们修改代理,以便根据jqGrid在url中放置的搜索参数过滤数据。 Indeed when working with remote data, jqGrid relies completely on the server to filter the data. 实际上,在处理远程数据时,jqGrid完全依赖服务器来过滤数据。 It simply appends query parameters to the url, where the parameter name is the column id and the parameter value is the value of the form element. 它只是将查询参数附加到url,其中参数名称是列id,参数值是表单元素的值。 For example: ?page_name=home&row_timestamp=2014-2-01_2014-2-28 if you have entered "home" in the text field of "CF template" and "February" in the dropdown of "Error date". 例如: ?page_name=home&row_timestamp=2014-2-01_2014-2-28如果您在“错误日期”下拉列表中的“CF模板”和“二月”的文本字段中输入了“主页”。

So the first thing we need is a way to parse the query parameters of the URL. 所以我们首先需要的是一种解析URL查询参数的方法。 You could use a jQuery plug-in, write your own, or ask StackOverlfow :) 您可以使用jQuery插件,编写自己的插件,或者询问StackOverlfow :)

function getParameterByName(url, name) {
    name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
    var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
        results = regex.exec(url);
    return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}

Then a function to filter the data. 然后是一个过滤数据的函数。 The design will be mostly up to you and your requirements (you could imagine making this easier by using jLing, just like jqGrid did). 设计将主要取决于您和您的要求(您可以想象使用jLing使这更容易,就像jqGrid一样)。 I used a basic example where we want to filter the row_id based on a range. 我使用了一个基本示例,我们希望根据范围过滤row_id The row_id parameter is split with _ to parse the bounds of the range. row_id参数用_分割以解析范围的边界。 Note that in my example I consider only row_id , but you will have to write the filter for all the columns, even the ones that were taken care of by jqGrid previously (the proxy has to behave like the server would). 请注意,在我的示例中,我只考虑row_id ,但您必须为所有列编写过滤器,甚至是之前由jqGrid处理过的列(代理必须像服务器一样)。

//Filtering split in two functions: 
// -one to parse the url and identify what filters to apply
// -one to do the actual filtering

function getFilterOptions(url) {
    var filterOptions = {};
    var row_id = getParameterByName(url, "row_id"); 
    if (row_id && row_id != "*") { //"*" == Any
        filterOptions.row_id = row_id.split("_");
    }
    return filterOptions;
}

//Uses Array.filter(), may require a polyfill on older browsers
function filterData(data, filterOptions) {
    return data.filter(function(row) { 
        if (filterOptions.row_id) {
            return filterOptions.row_id[0] <= row.row_id 
                && row.row_id <= filterOptions.row_id[1]
        }
        return true;
    });
}

Then update the proxy to use the filter. 然后更新代理以使用过滤器。

$.ajaxTransport("json", function(options) {
  //options.url is the query sent by jqGrid, including search parameters
  if(options.url.indexOf(gridurl) === 0) {
    var filterOptions = getFilterOptions(options.url); 
    return {
      send: function(headers, completeCallback) {
        setTimeout(function(){
            //this is what jqGrid will receive.
            var filteredData = filterData(mydata, filterOptions);
            completeCallback(200, "success", {json: filteredData});
        }, 10);
      },
      abort: function() {
        //Do nothing
      }
    };
  }
});

And finally, activate the search in the jqGrid settings. 最后,在jqGrid设置中激活搜索。 I have replaced the joker value 0 with * , and the other values with the format <min>_<max> to be parsed by getFilterOptions() : 我用*替换了joker值0 ,并且getFilterOptions()解析了格式为<min>_<max>的其他值:

$("#grid1").jqGrid({
    url:       gridurl,
    datatype:  "json",
    height:    250,
    colNames:  ['CF Template', 'Error Date', 'Skey', 'Type', 'Summary'],
    colModel:  [{/* template column */},
               {/* date column */},
               {   
                name: 'row_id',
                index: 'row_id',
                width: 100,
                sorttype: 'int',
                search:true,
                stype:'select',
                searchoptions: {
                    value: {
                        '*':'Any', //Notice: joker used in getFilterOptions
                        '0_12000000000':'0 - 12000000000', 
                        '12000000000_24000000000':'12000000000 - 24000000000',
                        /* ... */
                    }
                    //no event handler
                }
               },
               /* ... */
               ],
    /* ... */
});

3. Finish the filter implementation, and enjoy! 3.完成过滤器实现,享受!

You still have a bit of work to do, namely designing and writing the actual filters, but you have a working solution to have a custom search in jqGrid. 你还有一些工作要做,即设计和编写实际的过滤器,但是你有一个工作的解决方案,可以在jqGrid中进行自定义搜索。 I tested it on a local set-up with your test data, didn't face any trouble. 我在测试数据的本地设置上测试了它,没有遇到任何麻烦。 Let me know if I forgot something while converting my code into this answer. 如果我在将代码转换为此答案时忘记了某些内容,请告诉我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM