Mike
Mike

Reputation: 1938

DataTables Individual Column searching

Is it possible to combine the Select Inputs and the Text Inputs? I use DataTables on several tables, always the same initialization. I would like to chose the column for the Select Inputs by the column header since the column that I want the select list on is not always in the same position. Then all the others I want to have the Text Inputs. This way I'll have one column that has the Select Inputs and all others that have the Text Inputs.

I have been able to implement the different Select and Text Inputs from these two examples. But I'm not good enough with jquery and javascript to figure out how to select the right column for the Select Input and have all the others be Text Inputs. The tables that I use can be anywhere from 3 columns to 75+ columns. And I want to select the column by the header name for the Select input.

And on top of all of this, is there a way to make the Select Input a MultiSelect Input? I am having it a selector for the state and would like to be able to select multiple states at once.

Here are the two different ways I've used for the Select and Text input:

initComplete: function ()
{
    this.api().columns([1]).every(function ()
    {
        var column = this;
        var select = $('<select><option value=""></option></select>')
                .appendTo($(column.footer()).empty())
                .on('change', function ()
                {
                    var val = $.fn.dataTable.util.escapeRegex(
                        $(this).val()
                    );
                    var strVal = val.replace("<div class='Scrollable'>", '');
                    strVal = strVal.replace("<\/div>", '');
                    column
                        .search(strVal ? /*'^' +*/ strVal /*+ '$'*/ : '', true, false)
                        .draw();
                });

        column.data().unique().sort().each(function (d, j)
        {
            var strValue = d.replace("<div class='Scrollable'>", '');
            strValue = strValue.replace("<\/div>", '');
            select.append('<option value="' + strValue + '">' + strValue + '</option>')
        });
    });
}
,
initComplete: function ()
{
    var api = this.api();

    // Apply the search
    api.columns().every(function ()
    {
        var that = this;

        $('input', this.footer()).on('keyup change', function ()
        {
            if (that.search() !== this.value)
            {
                that
                      .search(this.value)
                      .draw();
            }
        });
    });
}

EIDT

Using @Gyrocode's suggestion from below I now have this:

initComplete: function ()
{
    var api = this.api();

    // Apply the search
    api.columns('.dt-filter-text').every(function ()
    {
        var that = this;

        $('input', this.footer()).on('keyup change', function ()
        {
            if (that.search() !== this.value)
            {
                that
                  .search(this.value)
                  .draw();
            }
        });
    });
    api.columns('.dt-filter-select').every(function ()
    {
        var column = this;
        var select = $('<select><option value=""></option></select>')
            .appendTo($(column.footer()).empty())
            .on('change', function ()
            {
                var val = $.fn.dataTable.util.excapeRegex(
                    $(this).val()
                );
                var strVal = val.replace("<div class='Scrollable'>", "");
                strVal = strVal.replace("</div>", '');
                column
                    .search(strVal ? /*'^' +*/strVal /*+ '$'*/ : '', true, false)
                    .draw();
            });
        column.data().unique().sort().each(function (d, J)
        {
            var strValue = d.replace("<div class='Scrollable'>", '');
            strValue = strValue.replace("</div>", '');
            select.append('<option value="' + strValue + '">' + strValue + '</option>')
        });
    });
}

This almost works. When I select a value from the selector in the State column it doesn't search. I'm sure I'm missing something obvious, but I don't know what.

Also, it is not getting all the states, only the ones on the first page. Is there a way to get all the states or perhaps to have an array that will hold all the values that I need since the states are not likly to change?

Upvotes: 1

Views: 4955

Answers (2)

iDuck
iDuck

Reputation: 41

I've got it working. Just be sure to add classes to the header, like so:

<thead>
    <tr>
        <th class="dt-filter-text">Name</th>
        <th class="dt-filter-select">Position</th>
        <th class="dt-filter-select">Office</th>
        <th class="dt-filter-text">Age</th>
        <th class="dt-filter-text">Start date</th>
        <th class="dt-filter-text">Salary</th>
    </tr>
</thead>
<tfoot>
    <tr>
        <th>Name</th>
        <th>Position</th>
        <th>Office</th>
        <th>Age</th>
        <th>Start date</th>
        <th>Salary</th>
    </tr>
</tfoot>

JavaScript:

$(document).ready(function() {
    // DataTable
    $('#table').DataTable({
        initComplete: function () {

            //Apply select search
            this.api().columns('.dt-filter-select').every(function () {
                var column = this;
                var select = $('<select><option value=""></option></select>')
                    .appendTo($(column.footer()).empty())
                    .on('change', function () {
                        var val = $.fn.dataTable.util.escapeRegex(
                            $(this).val()
                        );
                        column
                            .search( val ? '^'+val+'$' : '', true, false)
                            .draw();
                    });
                column.data().unique().sort().each(function (d,j) {
                    select.append('<option value="'+d+'">'+d+'</option>')
                });
            });

            //Apply text search
            this.api().columns('.dt-filter-text').every(function () {
                var title = $(this.footer()).text();
                $(this.footer()).html('<input type="text" placeholder="Search '+title+'" />');
                var that = this;
                $('input',this.footer()).on('keyup change', function () {
                    if (that.search() !== this.value) {
                        that
                            .search(this.value)
                            .draw();
                    }
                });
            });
        }
    });
});

Add this to CSS if you want to place the footer directly below the header:

#table tfoot {
    display: table-header-group;
}

Upvotes: 4

Gyrocode.com
Gyrocode.com

Reputation: 58920

You need to specify column indexes for columns() API method to target specific columns.

For example:

initComplete: function ()
{
    // Initialize dropdown filter in second column
    this.api().columns([1]).every(function ()
    {
       // ... skipped ...
    });

    // Initialize text filter in first, third and fourth column
    this.api().columns([0, 2, 3]).every(function ()
    {
       // ... skipped ...
    });
}

However, instead of dealing with column indexes, I would assign a class name to each th element where you want a text box (dt-filter-text) or dropdown (dt-filter-select). Then you can supply a selector to columns() API method, for example columns('.dt-filter-text') or columns('.dt-filter-select').

Upvotes: 1

Related Questions