2014 年 9 月 22 日星期一

字母輸入搜尋 - 第三部分

在本系列文章的最後一部分中,我將詳細說明如何將本系列前兩部分中建立的字母搜尋轉換為 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 建立功能外掛程式。基本概念是,我們需要註冊一個新的功能外掛程式,該外掛程式可以透過 $.fn.dataTable.ext.feature 陣列與 dom 一起使用。我們提供要註冊的字母和一個回呼函式,當外掛程式要用於 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 的多表格層面,但完全可以使用 $('table.dataTable').DataTable().alphabetSearch( 'A' ); 在頁面上的所有表格中搜尋 A,因為使用了上述 iterator()

為了完整起見,我們也建立一個可用於重新分組資料的方法 - 更新每個字母滑鼠移過時顯示的計數

$.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'
} );


}());