Search code examples
jquerykendo-uitelerikkendo-griddatasource

Parsing kendo grid filter strings into filter objects


I've created a pseudo-grid widget of sorts (basically just a grid header) to allow the user to configure sorts and filters to their liking, and then save those configurations for future use. The issue is that they're returned from the database as strings. Unfortunately, I need a method of converting them back into javascript objects so I can apply them to the grid.

I'm using the parameterMap function below to convert a DataSourceRequest object into something that can be posted to the controller action and saved in the database. The function just takes the objects returned from the kendoGrid.dataSource and turns them into a query string of sorts. So, this:

    // Get datasource of the filter grid, so we can save the search applied to it.
    var f = $("#filter-grid").data("kendoGrid").dataSource;

    // Set the filtering/sorting applied to the filter grid in the model being saved.
    e.model.Request = e.sender.dataSource.transport.parameterMap({
        filter: f.filter(),
        group: f.group(),
        page: f.page(),
        pageSize: f.pageSize(),
        sort: f.sort()
    });

returns this:

    Object {
        sort: "InvoiceNumber-asc", 
        page: 1, 
        pageSize: 100, 
        group: "", 
        filter: "Auditor~startswith~'Gabe'~and~Auditor~endswith~'Newell'"
    }

Is there any javascript function provided with the Kendo UI stuff that allows for parsing a query string into a javascript object? I basically want to reverse the results of the parameterMap() function. My ultimate goal is to avoid rolling my own method of parsing these strings back into objects, and it seems likely that something in the Kendo suite should take care of this for me.

The Telerik documentation does provide a method to perform exactly what I'm looking for (GridCommand.Parse()), but that's available in the controller and I need this to be done on the page. If I can find something akin to that MVC extension provided in their jQuery-based framework, then this just got considerably easier to implement.

Thanks in advance.


Solution

  • After asking on the Telerik forums, apparently there isn't a method of doing this provided in the Telerik jQuery framework. So, I went ahead and just implemented one.

    Here is the link to the jsfiddle if anyone is curious. It only supports filter strings and sort strings, since I have no use for parsing group strings yet.

    Filter strings:

    function parseFilterString(filterString) {
    
            // sample filter: "(Auditor~startswith~'Gabe'~and~Auditor~endswith~'Newell')~and~(Company~contains~'Valve'~and~Company~neq~'EA')";
    
            // Remove all of the ' characters from the string.
            filterString = filterString.replace(/[']/g, '');
    
            // Split the string into an array of strings, using the ~ as a delimiter.
            var ss = filterString.split("~"); // ss stands for "split string". I'm clever.
    
            var F = []; // Used to store all of the parsed filters.
            var fIndex = -1; // Used to track filter index.
            var cIndex = 0; // Used to track filter index within a composite filter object.
            var isComposite = false; // Used to indicate if a composite filter is currently being parsed.
    
            for (var i = 0; i < ss.length; i++) {
                if (i % 4 == 0) { // Field.
                    if (ss[i].indexOf('(') > -1) { // If we're starting a composite object, create a composite object and add it to the parsed filters.
                        F.push({
                            filters: [],
                            logic: ""
                        });
                        fIndex++; // We added an object to the array, so increment the counter.
                        F[fIndex]
                        F[fIndex].filters.push({
                            field: ss[i].replace('(', ''),
                            operator: "",
                            value: ""
                        });
                        cIndex = 0; // We added the first filter to the composite object, so set the counter.
                        isComposite = true;
                    }
                    else if (isComposite) { // If we're parsing the second filter in a composite filter object, then add the field to the child filter.
                        F[fIndex].filters.push({
                            field: ss[i],
                            operator: "",
                            value: ""
                        });
                        cIndex++; // We added the second filter to the composite object, so increment the counter.
                    }
                    else { // Add the field as normal.
                        F.push({
                            field: ss[i],
                            operator: "",
                            value: ""
                        });
                        fIndex++; // We added an object to the array, so increment the counter.
                    }
                }
                if (i % 4 == 1) { // Operator.
                    if (isComposite) {
                        F[fIndex].filters[cIndex].operator = ss[i];
                    }
                    else {
                        F[fIndex].operator = ss[i];
                    }
                }
                if (i % 4 == 2) { // Value.
                    if (ss[i].indexOf(')') > -1) {
                        F[fIndex].filters[cIndex].value = ss[i].replace(')', '');
                        isComposite = false;
                    }
                    else if (isComposite) {
                        F[fIndex].filters[cIndex].value = ss[i];
                    }
                    else {
                        F[fIndex].value = ss[i];
                    }
                }
                if (i % 4 == 3) { // Logic.
                    if (isComposite) {
                        F[fIndex].logic = ss[i]; // Add the logic to the composite filter object.
                    }
                    // If the filter is not composite, the logic will always be "and". So, we just don't do anything if that's the case.
                }
            }
    
            return {
                filters: F,
                logic: "and"
            };
        };
    

    Sort strings:

    function parseSortString(sortString) {
            // sample multi-level sort: "Auditor-asc~Company-desc~Invoice-asc";
    
            // Split the string into an array of strings, using the ~ as a delimiter.
            var ss = sortString.split("~"); // ss stands for "split string". I'm clever.
    
            var S = []; // Array containing sort objects.
    
            for (var i = 0; i < ss.length; i++) {
                var sort = ss[i].split('-'); // Split sort string into field and direction.
                S.push({
                    compare: undefined, // This field exists in the sort objects, but is always undefined (as far as I can tell). I added it anyways, to minimize potential future issues.
                    dir: sort[1], // Direction.
                    field: sort[0] // Field.
                });
            }
    
            return S;
        };