2014年9月22日,星期一

字母输入搜索 - 第三部分

在本系列文章的最后一部分,我们将探讨 DataTables 的一些搜索选项和 API 以扩展 DataTables,我将详细介绍如何将 字母搜索 (在本系列的前两部分中创建)转换为 DataTables 的 功能插件,并使用 API 扩展方法 来控制我们创建的新功能。

最终结果是 DataTables 的一个可自定义扩展,可以使用简单的初始化轻松地重用于任何网页上的一个或多个表格

var table = $('#example').DataTable( {
    layout: {
        top1: 'alphabetSearch'
    }
} );

或者如果您使用的是旧版 DataTables 1.x

var table = $('#example').DataTable( {
    dom: 'Alfrtip'
} );

请注意 dom 的使用,以指定使用的表格控件元素 - A 是我们的新插件。这就是使用它的全部内容!

在我们深入代码之前,最终结果现在可以在 DataTables CDN 上获得(Javascript / CSS),并且下面显示了结果表格的演示(其功能与 第二部分 中创建的功能相同)。

姓名职位办公室年龄开始日期薪水
Tiger Nixon系统架构师爱丁堡612011-04-25$320,800
Garrett Winters会计东京632011-07-25$170,750
Ashton Cox初级技术作家旧金山662009-01-12$86,000
Cedric Kelly高级 Javascript 开发人员爱丁堡222012-03-29$433,060
Airi Satou会计东京332008-11-28$162,700
Brielle Williamson集成专家纽约612012-12-02$372,000
Herrod Chandler销售助理旧金山592012-08-06$137,500
Rhona Davidson集成专家东京552010-10-14$327,900
Colleen HurstJavascript 开发人员旧金山392009-09-15$205,500
Sonya Frost软件工程师爱丁堡232008-12-13$103,600
Jena Gaines办公室经理伦敦302008-12-19$90,560
Quinn Flynn支持主管爱丁堡222013-03-03$342,000
Charde Marshall区域总监旧金山362008-10-16$470,600
Haley Kennedy高级营销设计师伦敦432012-12-18$313,500
Tatyana Fitzpatrick区域总监伦敦192010-03-17$385,750
Michael Silva营销设计师伦敦662012-11-27$198,500
Paul Byrd首席财务官 (CFO)纽约642010-06-09$725,000
Gloria Little系统管理员纽约592009-04-10$237,500
Bradley Greer软件工程师伦敦412012-10-13$132,000
Dai Rios人事主管爱丁堡352012-09-26$217,500
Jenette Caldwell开发主管纽约302011-09-03$345,000
Yuri Berry首席营销官 (CMO)纽约402009-06-25$675,000
Caesar Vance售前支持纽约212011-12-12$106,450
Doris Wilder销售助理悉尼232010-09-20$85,600
Angelica Ramos首席执行官 (CEO)伦敦472009-10-09$1,200,000
Gavin Joyce开发人员爱丁堡422010-12-22$92,575
Jennifer Chang区域总监新加坡282010-11-14$357,650
Brenden Wagner软件工程师旧金山282011-06-07$206,850
Fiona Green首席运营官 (COO)旧金山482010-03-11$850,000
Shou Itou区域营销东京202011-08-14$163,000
Michelle House集成专家悉尼372011-06-02$95,400
Suki Burks开发人员伦敦532009-10-22$114,500
Prescott Bartlett技术作家伦敦272011-05-07$145,000
Gavin Cortez团队领导旧金山222008-10-26$235,500
Martena Mccray售后支持爱丁堡462011-03-09$324,050
Unity Butler营销设计师旧金山472009-12-09$85,675
Howard Hatfield办公室经理旧金山512008-12-16$164,500
Hope Fuentes秘书旧金山412010-02-12$109,850
Vivian Harrell财务总监旧金山622009-02-14$452,500
Timothy Mooney办公室经理伦敦372008-12-11$136,200
Jackson Bradshaw总监纽约652008-09-26$645,750
Olivia Liang支持工程师新加坡642011-02-03$234,500
Bruno Nash软件工程师伦敦382011-05-03$163,500
Sakura Yamamoto支持工程师东京372009-08-19$139,575
Thor Walton开发人员纽约612013-08-11$98,540
Finn Camacho支持工程师旧金山472009-07-07$87,500
Serge Baldwin数据协调员新加坡642012-04-09$138,575
Zenaida Frank软件工程师纽约632010-01-04$125,250
Zorita Serrano软件工程师旧金山562012-06-01$115,000
Jennifer Acosta初级 Javascript 开发人员爱丁堡432013-02-01$75,650
Cara Stevens销售助理纽约462011-12-06$145,600
Hermione Butler区域总监伦敦472011-03-21$356,250
Lael Greer系统管理员伦敦212009-02-27$103,500
Jonas Alexander开发人员旧金山302010-07-14$86,500
Shad Decker区域总监爱丁堡512008-11-13$183,000
Michael BruceJavascript 开发人员新加坡292011-06-27$183,000
Donna Snider客户支持纽约272011-01-25$112,000
姓名职位办公室年龄开始日期薪水

值得注意的是,我假设您熟悉在本系列的 第一部分第二部分 中开发的代码。由于此功能插件所需的大部分代码已在这些文章中开发,因此我将缩短这些代码块。这篇文章只是关于将代码重新排列成 DataTables 的可重用插件。

功能插件

手册的 功能插件部分 详细描述了如何为 DataTables 创建功能插件。基本原理是,我们需要注册一个新的功能插件,该插件可以通过 dom 通过 $.fn.dataTable.ext.feature 数组使用。我们提供要注册的字母和一个回调函数,该函数在将插件用于 DataTable 时执行 - 此回调必须返回要插入文档中的控件节点,在本例中为字母搜索栏。

$.fn.dataTable.ext.feature.push( {
    fnInit: function ( settings ) {
        var search = new $.fn.dataTable.AlphabetSearch( settings );
        return search.node();
    },
    cFeature: 'A'
} );

在上面的代码中,我们注册字符 A 并创建 $.fn.dataTable.AlphabetSearch 的新实例,从其自己的 API node() 方法返回节点。

$.fn.dataTable.AlphabetSearch 在我们的代码中是新的,但它只是先前开发的创建字母搜索输入节点的代码的封装

$.fn.dataTable.AlphabetSearch = function ( context ) {
    var table = new $.fn.dataTable.Api( context );
    var alphabet = $('<div class="alphabet"/>');

    // Bin the data and create the alphabet search input element
    ...

    // API method to get the alphabet container node
    this.node = function () {
        return alphabet;
    };
};

请注意添加了 node() API 方法,该方法可用于获取容器节点,如上文 DataTables 功能的注册中所做的那样。

备选初始化

值得指出的是,字母搜索也可以使用 new $.fn.dataTable.AlphabetSearch() 直接初始化,而不是使用 dom 选项。如果您愿意,这可以提高灵活性并更好地控制字母栏的插入位置

var table = $('#myTable').DataTable();
var search = new $.fn.dataTable.AlphabetSearch();

$( search.node() ).appendTo( ... ); // insert into document

搜索插件更新

以前,搜索插件 使用变量 _alphabetSearch 来确定要搜索的字母,但是该变量没有隔离到单个表格 - 它将应用于页面上的所有表格。这对于可重用组件不适用,因此我们需要使用其他方法来存储要搜索的字母。

为此,我们可以使用 DataTables 设置对象,该对象在页面上的每个表格中都是全局唯一的(在许多 API 文档中,设置对象被称为“上下文”)。通过简单地将我们的参数附加到设置对象,我们始终可以为该表格访问它。请考虑以下对我们在第一部分中开发的搜索插件的更新

$.fn.dataTable.ext.search.push( function ( context, searchData ) {
    // Ensure that there is a search applied to this table before running it
    if ( ! context.alphabetSearch ) {
        return true;
    }

    if ( searchData[0].charAt(0) === context.alphabetSearch ) {
        return true;
    }

    return false;
} );

更改只是使用 context.alphabetSearch 而不是 _alphabetSearch。现在要触发搜索,我们只需要设置该参数,这就是 API 插件发挥作用的地方。

API 插件

一个 API 插件 可以扩展 DataTables 提供的 默认 API 方法集,在本例中,我们希望添加设置每个表格的 alphabetSearch 参数的功能。我们可以使用以下方法非常轻松地做到这一点

$.fn.dataTable.Api.register( 'alphabetSearch()', function ( searchTerm ) {
    this.iterator( 'table', function ( context ) {
        context.alphabetSearch = searchTerm;
    } );

    return this;
} );

上面 iterator() 方法用于遍历 API 实例上下文中每个表格并设置搜索词。尽管我们的功能插件没有利用 DataTables API 的多表格方面,但由于使用了 iterator(),因此完全可以使用 $('table.dataTable').DataTable().alphabetSearch( 'A' ); 在页面上的所有表格中搜索 A

为了完整起见,我们还创建了一个方法,该方法可用于重新绑定数据 - 更新每个字母的计数,如鼠标悬停时所示

$.fn.dataTable.Api.register( 'alphabetSearch.recalc()', function ( searchTerm ) {
    this.iterator( 'table', function ( context ) {
        draw(
            new $.fn.dataTable.Api( context ),
            $('div.alphabet', this.table().container()) );
        );
    } );

    return this;
} );

这使用了 draw() 方法,该方法只是一个封装先前开发的绘制代码的函数。它传递当前表格的 API 实例和相关表格的字母搜索 DOM 节点。

最终代码

我们已经完成了对 DataTables 扩展世界的探索,我希望您发现这对于如何创建可重用插件以根据您的需要自定义 DataTables 很有用。

与往常一样,非常欢迎您对这篇文章以及 DataTables 的任何其他方面提供 反馈

在本系列文章中开发的最终代码如下所示,并且可以在 DataTables CDN 上获得(Javascript / CSS)。

(function(){


// Search function
$.fn.dataTable.Api.register( 'alphabetSearch()', function ( searchTerm ) {
    this.iterator( 'table', function ( context ) {
        context.alphabetSearch = searchTerm;
    } );

    return this;
} );

// Recalculate the alphabet display for updated data
$.fn.dataTable.Api.register( 'alphabetSearch.recalc()', function ( searchTerm ) {
    this.iterator( 'table', function ( context ) {
        draw(
            new $.fn.dataTable.Api( context ),
            $('div.alphabet', this.table().container())
        );
    } );

    return this;
} );


// Search plug-in
$.fn.dataTable.ext.search.push( function ( context, searchData ) {
    // Ensure that there is a search applied to this table before running it
    if ( ! context.alphabetSearch ) {
        return true;
    }

    if ( searchData[0].charAt(0) === context.alphabetSearch ) {
        return true;
    }

    return false;
} );


// Private support methods
function bin ( data ) {
    var letter, bins = {};

    for ( var i=0, ien=data.length ; i<ien ; i++ ) {
        letter = data[i].charAt(0).toUpperCase();

        if ( bins[letter] ) {
            bins[letter]++;
        }
        else {
            bins[letter] = 1;
        }
    }

    return bins;
}

function draw ( table, alphabet )
{
    alphabet.empty();
    alphabet.append( 'Search: ' );

    var columnData = table.column(0).data();
    var bins = bin( columnData );

    $('<span class="clear active"/>')
        .data( 'letter', '' )
        .data( 'match-count', columnData.length )
        .html( 'None' )
        .appendTo( alphabet );

    for ( var i=0 ; i<26 ; i++ ) {
        var letter = String.fromCharCode( 65 + i );

        $('<span/>')
            .data( 'letter', letter )
            .data( 'match-count', bins[letter] || 0 )
            .addClass( ! bins[letter] ? 'empty' : '' )
            .html( letter )
            .appendTo( alphabet );
    }

    $('<div class="alphabetInfo"></div>')
        .appendTo( alphabet );
}


$.fn.dataTable.AlphabetSearch = function ( context ) {
    var table = new $.fn.dataTable.Api( context );
    var alphabet = $('<div class="alphabet"/>');

    draw( table, alphabet );

    // Trigger a search
    alphabet.on( 'click', 'span', function () {
        alphabet.find( '.active' ).removeClass( 'active' );
        $(this).addClass( 'active' );

        table
            .alphabetSearch( $(this).data('letter') )
            .draw();
    } );

    // Mouse events to show helper information
    alphabet
        .on( 'mouseenter', 'span', function () {
            alphabet
                .find('div.alphabetInfo')
                .css( {
                    opacity: 1,
                    left: $(this).position().left,
                    width: $(this).width()
                } )
                .html( $(this).data('match-count') );
        } )
        .on( 'mouseleave', 'span', function () {
            alphabet
                .find('div.alphabetInfo')
                .css('opacity', 0);
        } );

    // API method to get the alphabet container node
    this.node = function () {
        return alphabet;
    };
};

$.fn.DataTable.AlphabetSearch = $.fn.dataTable.AlphabetSearch;


// Register a search plug-in
$.fn.dataTable.ext.feature.push( {
    fnInit: function ( settings ) {
        var search = new $.fn.dataTable.AlphabetSearch( settings );
        return search.node();
    },
    cFeature: 'A'
} );


}());