Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Child rows + filter widget + Multiple Headers #113

Open
smu2015 opened this Issue · 15 comments

3 participants

@smu2015

Hello,

i would like to create a table with :

  • 2 rows for the headers (for childrow)
  • Filter for each cells

The filter work only for the first row of the thead.

Do you know an issue for my problem plz ?
Very sry for my english :) I'm french

@thezoggy
Collaborator

http://mottie.github.com/tablesorter/docs/#Configuration

check out the 'filter_childRows' option

@smu2015

Thank you for your answer :)

I use this parameter (filter_childRows : true) but i search for a search's input who is looking only in child rows like this :

http://hpics.li/4ce1b37

@Mottie
Owner

HI smu2015!

What filter program are you using? That doesn't look like the filter widget provided with the plugin. Did you see this demo?

@smu2015

Hi :)

I'm using your jquery.tablesorter.widgets.js and i try to create a type "Filter_multiple".
It's homemade but my beginner's level in jQuery don't permiss me more :)

@smu2015

And yes, i have see the demo.
But i would like search only on :

  • childRow without primary
  • Primary without Childrow

Congratulation for your tablesorter, it's very cool and easy. It's a pleasure to use it

@Mottie
Owner

If you have any code you would like to share, I would like to see it. But right now, I am very busy with updating to version 2.4 and starting work on version 3.0, so I may not have time to modify the current filter widget for you; but if you already have something written, I don't mind helping.

Maybe there is another filter plugin somewhere that can be modified?

@smu2015

I have just copy your widget filter and try to adapt for my table.

The modif is principaly on : http://hpics.li/7295819

I know, it's not a good modification but i try :)

// code removed to avoid confusion, but thank you anyway :)
@Mottie
Owner

Ok, I didn't spend too much time with this, but I didn't notice any errors and I think it's working as it should. I'm not sure if I plan on officially supporting this mod, but if you have any problems, please feel free to post here.

This filter widget mod will not:

  • Add a select dropdown
  • Use filter functions ( no filter_functions option )
  • Include child row text ( no filter_childRows option )
  • Allow using parsed data for child rows

This demo has a rowspan in the first cell, but I don't think it matters; and I don't have your HTML to test it.

Here is a demo

To set this filter widget up, you need to add an extra tbody with all of your filters. Each filter has a data-column="#" in which the # matches the column number (zero-based index, but ignore rowspan & colspan cells).

<tbody class="tablesorter-infoOnly">
    <tr class="tablesorter-filter-row">
        <td colspan="5">
            Order #: <input type="search" placeholder="" data-column="0">
            Customer: <input type="search" placeholder="" data-column="1">
            PO: <input type="search" placeholder="" data-column="2">
            Date: <input type="search" placeholder="" data-column="3">
            Total: <input type="search" placeholder="" data-column="4">
            Address: <input type="search" placeholder="" data-column="5">
            City/State: <input type="search" placeholder="" data-column="6">
            Zip: <input type="search" placeholder="" data-column="7">
            Notes: <input type="search" placeholder="" data-column="8">
        </td>
    </tr>
</tbody>

and here is the filter widget mod code

/* Widget: modified filter (7/27/2012)
 widgetOptions:
  filter_cssFilter     : 'tablesorter-filter' // css class name added to the filter row & each input in the row
  filter_ignoreCase    : true   // if true, make all searches case-insensitive
  filter_reset         : null   // jQuery selector string of an element used to reset the filters
  filter_searchDelay   : 300    // typing delay in milliseconds before starting a search
  filter_startsWith    : false  // if true, filter start from the beginning of the cell contents
  filter_useParsedData : false  // filter all data using parsed content
 **************************/
$.tablesorter.addWidget({
    id: "filter",
    format: function(table) {
        if (table.config.parsers && !$(table).hasClass('hasFilters')) {
            var i, j, k, l, cv, v, val, ff, x, xi, cr, st, sel, str,
            ft, ft2, $tb, $th, $tr, $td, rg, r, s, t, dis, col,
            last = '', // save last filter search
            ts = $.tablesorter,
            c = table.config,
            $ths = $(c.headerList),
            wo = c.widgetOptions,
            css = wo.filter_cssFilter || 'tablesorter-filter',
            $t = $(table).addClass('hasFilters'),
            b = $t.children('tbody:not(.' + c.cssInfoBlock + ')'),
            cols = c.parsers.length,
            reg = [ // regex used in filter "check" functions
                /^\/((?:\\\/|[^\/])+)\/([mig]{0,3})?$/, // 0 = regex to test for regex
                new RegExp(c.cssChildRow), // 1 = child row
                /undefined|number/, // 2 = check type
                /(^[\"|\'|=])|([\"|\'|=]$)/, // 3 = exact match
                /[\"\'=]/g, // 4 = replace exact match flags
                /[^\w,. \-()]/g, // 5 = replace non-digits (from digit & currency parser)
                /[<>=]/g // 6 = replace operators
            ],
            parsed = $ths.map(function(i){
                return (ts.getData) ? ts.getData($ths.filter('[data-column="' + i + '"]:last'), c.headers[i], 'filter') === 'parsed' : $(this).hasClass('filter-parsed');
            }).get(),
            time, timer,

            // dig fer gold
            findRows = function(filter){
                var $tb, $tr, $td, cr, r, v, cv, l, ff, time, arry;
                if (c.debug) { time = new Date(); }
                arry = $.isArray(filter);
                v = (arry) ? filter : $t.find('tbody').eq(0).children('tr').find('input.' + css).map(function(){
                    return $(this).val() || '';
                }).get();
                cv = (v || []).join(''); // combined filter values
                // return if the last search is the same; but filter === false when updating the search
                // see example-widget-filter.html filter toggle buttons
                if (last === cv && filter !== false) { return; }

                $t.trigger('filterStart');
                for (k = 0; k < b.length; k++ ) {
                    $tb = $(b[k]).hide();
                    $tr = $tb.children('tr');
                    l = $tr.length;
                    if (cv === '') {
                        $tr.show().removeClass('filtered');
                    } else {
                        // loop through the rows
                        for (j = 0; j < l; j++) {
                            // skip child rows
                            if (reg[1].test($tr[j].className)) { continue; }
                            r = true;
                            cr = $tr.eq(j).nextUntil('tr:not(.' + c.cssChildRow + ')');
                            $td = $tr.eq(j).add(cr).children('td');
                            for (i = 0; i < v.length; i++) {
                                // ignore if filter is empty or disabled
                                if (v[i]) {
                                    // check if column data should be from the cell or from parsed data
                                    if (wo.filter_useParsedData || parsed[i]) {
                                        x = c.cache[k].normalized[j][i];
                                    } else {
                                    // using older or original tablesorter
                                        x = $.trim($td.eq(i).text());
                                    }
                                    xi = !reg[2].test(typeof x) && wo.filter_ignoreCase ? x.toLocaleLowerCase() : x;
                                    ff = r; // if r is true, show that row
                                    // val = case insensitive, v[i] = case sensitive
                                    val = wo.filter_ignoreCase ? v[i].toLocaleLowerCase() : v[i];
                                    if (reg[0].test(val)) {
                                        rg = reg[0].exec(val);
                                        try {
                                            ff = new RegExp(rg[1], rg[2]).test(xi);
                                        } catch (err) {
                                            ff = false;
                                        }
                                    // Look for quotes or equals to get an exact match
                                    } else if (reg[3].test(val) && xi === val.replace(reg[4], '')) {
                                        ff = true;
                                    // Look for a not match
                                    } else if (/^\!/.test(val)) {
                                        val = val.replace('!','');
                                        s = xi.search($.trim(val));
                                        ff = val === '' ? true : !(wo.filter_startsWith ? s === 0 : s >= 0);
                                    // Look for operators >, >=, < or <=
                                    } else if (/^[<>]=?/.test(val)) {
                                        rg = $.tablesorter.formatFloat(xi.replace(reg[5], ''), table);
                                        if (isNaN(rg)) { rg = xi; }
                                        s = $.tablesorter.formatFloat(val.replace(reg[5], '').replace(reg[6],''), table);
                                        if (/>/.test(val)) { ff = />=/.test(val) ? rg >= s : rg > s; }
                                        if (/</.test(val)) { ff = /<=/.test(val) ? rg <= s : rg < s; }
                                    // Look for wild card: ? = single, or * = multiple
                                    } else if (/[\?|\*]/.test(val)) {
                                        ff = new RegExp( val.replace(/\?/g, '\\S{1}').replace(/\*/g, '\\S*') ).test(xi);
                                    // Look for match, and add child row data for matching
                                    } else {
                                        x = (xi + t).indexOf(val);
                                        ff  = ( (!wo.filter_startsWith && x >= 0) || (wo.filter_startsWith && x === 0) );
                                    }
                                    r = (ff) ? (r ? true : false) : false;
                                }
                            }
                            $tr[j].style.display = (r ? '' : 'none');
                            $tr.eq(j)[r ? 'removeClass' : 'addClass']('filtered');
                            if (cr.length) { cr[r ? 'show' : 'hide'](); }
                        }
                    }
                    $tb.show();
                }

                last = cv; // save last search
                if (c.debug) {
                    ts.benchmark("Completed filter widget search", time);
                }
                $t.trigger('applyWidgets'); // make sure zebra widget is applied
                $t.trigger('filterEnd');
            };

            if (c.debug) {
                time = new Date();
            }
            wo.filter_ignoreCase = wo.filter_ignoreCase !== false; // set default filter_ignoreCase to true
            wo.filter_useParsedData = wo.filter_useParsedData === true; // default is false
            $t
            .bind('addRows updateCell update appendCache search'.split(' ').join('.tsfilter') + '.tsfilter', function(e, filter){
                findRows(e.type === 'search' ? filter : '');
            })
            .find('.tablesorter-filter-row')
            .find('input')
            .addClass(css)
            .bind('keyup search', function(e, filter){
                // ignore arrow and meta keys; allow backspace
                if ((e.which < 32 && e.which !== 8) || (e.which >= 37 && e.which <=40)) { return; }
                // skip delay
                if (typeof filter !== 'undefined') {
                    findRows(filter);
                    return false;
                }
                // delay filtering
                clearTimeout(timer);
                timer = setTimeout(function(){
                    findRows();
                }, wo.filter_searchDelay || 300);
            });

            // reset button/link
            if (wo.filter_reset && $(wo.filter_reset).length) {
                $(wo.filter_reset).bind('click', function(){
                    $t.find('.' + css).val('');
                    findRows();
                    return false;
                });
            }

            if (c.debug) {
                ts.benchmark("Applying Filter widget", time);
            }
        }
    }
});
@smu2015

Hi :)
Thank a lot for your help.
I've tried to use the code.
i have make a fiddle, i have just change HTML and class for childRow :
http://jsfiddle.net/smu2015/D6HHf/5/

But i don't know if it's me but data-column don't seem work.
They are a problem too with a keyword. In your example, if i write 'defined' on your "Order #:" filter, i have all result.

Very thank for your time

Edit : Change icon

@Mottie
Owner

I've been too busy to work on this, but I should have it for you soon.

@Mottie
Owner

The filter widget should properly target columns when multiple header rows with column and row spans are included in version 2.4. Please test it out for me. Thanks!

@Mottie Mottie closed this
@smu2015

Hi !
I'm currently testing the version 2.4.
/clap for your saveSort, very cool.
i'm looking for multiple rows like you show me in http://jsfiddle.net/eY8uH/80/ but i didn't see the option in 2.4
Can you help me out plz ?

Thank you

@Mottie
Owner

Hi smu2015!

Here, I've updated the demo with the new theme option.

Basically, you'll need to copy the filter widget code from that demo. I didn't make the filter widget work on multiple rows by default. It's already so huge that I thought I'd wait until I got version 3 done. Then you can build your own plugin.

@Mottie Mottie reopened this
@smu2015

Thank you it works, though I've noted a small defect: when I enter the letters composing the key word "undefined" in a search field, all records are returned.

@Mottie
Owner

Hmm, ok I'll look into that. Thanks!

@Mottie Mottie modified the milestone: Abelt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.