Плагины jQuery — итерация с .each и (this)

Я пытаюсь написать плагин, который можно прикрепить к элементу таблицы следующим образом:

jQuery("#tableid").excelify();

Таблица будет примерно такой (в данном примере это мусорные данные):

<table id="tableid">
<thead>
<tr>
<th>Order</th>
<th>User</th>
<th>Product</th>
<th>Total</th>
</tr>
</thead>

<tbody>
<tr>
    <td data-format="bold">3145</td>
    <td data-format="bold underline">James</td>
    <td>Pens</td>
    <td>230.55</td>
</tr>

<tr>
    <td>31435</td>
    <td>Rich</td>
    <td>Bags</td>
    <td>3320.55</td>
</tr>

<tr>
    <td>4145</td>
    <td>Dobby</td>
    <td>baloons</td>
    <td>30.55</td>
</tr>
</tbody>

<tfoot>
<tr>
    <td></td>
    <td></td>
    <td>TOTAL</td>
    <td>9999.99</td>
</tr>
</tfoot>

The idea behind the plugin is to iterate the THEAD, TBODY and TFOOT and return each of these as JSON data which can then be sent to a separate PHP page and converted into an Excel sheet.

У меня проблема в том, что в моем плагине (это) относится к элементу, к которому я прикрепляю плагин - в данном случае это идентификатор таблицы "#tableid".

Теперь плагин ищет THEAD, TBODY и TFOOT и перебирает в нем th, td и т.д. Однако это не работает при работе внутри плагина. Я думаю, это потому, что (это) в операторах .each сбивает с толку родитель (это) - фактический объект таблицы.

Когда я запускаю плагин, он возвращает полные данные JSON, тогда как если я запускаю его вне плагина и просто встраиваю в главную страницу, он работает отлично.

Прав ли я в своем предположении, что .each и (this) перепутаны?

Вот мой код плагина:

(function ( $ ) {

$.fn.excelify = function() {
    //Build the Header Rows
    var header = Array();
    jQuery("#" + this.id + " tr th").each(function(i, v){
        header[i] = jQuery(this).text();
    });

    //Write the Footer JSON data to a hidden field on the calling page called "header"
    jQuery("#header").val(JSON.stringify(header));

    //build the Data Rows
    var data = Array();
    jQuery("#" + this.id + " tbody tr").each(function(i, v){
        data[i] = Array();
        jQuery(this).children('td').each(function(ii, vv){

            //if the data is delimited with a pipe, then there is also formatting information, such as Bold
            if(jQuery(this).data('format')) {
                data_format = jQuery(this).data('format');
            } else {
                data_format = "";
            }

            value = jQuery(this).text();
            data[i][ii] = data_format + "|" + value;
        });
    });

    //Write the Tbody JSON data to a hidden field on the calling page called "rows"
    jQuery("#rows").val(JSON.stringify(data));

    //Build the Footer Rows
    var footer = Array();
    jQuery("#" + this.id + " tfoot tr td").each(function(i, v){
        footer[i] = jQuery(this).text();
    });

    //Write the Footer JSON data to a hidden field on the calling page called "footer"
    jQuery("#footer").val(JSON.stringify(footer));


    //Submit the form
    jQuery("#convert_form").submit();
};

}(jQuery));

Итак, чтобы подчеркнуть проблему, я думаю, что (это) в первой части кода итерации .each это то, что терпит неудачу:

jQuery("#" + this.id + " tr th").each(function(i, v){
        **//is the (this) on the line below referring to the Plugin's (this)?**
        header[i] = jQuery(this).text();
    });

Любая помощь будет оценена по достоинству. Огромное спасибо

Джеймс


person James Stoddern    schedule 16.11.2015    source источник
comment
//это (это) в строке ниже относится к плагину (это)? нет, это относится к текущему th.   -  person Kevin B    schedule 16.11.2015
comment
Использовали ли вы отладчик JavaScript, выполняли ли вы пошаговый код и проверяли ли значение 'this' там, где вы ожидаете, что оно будет иметь неправильное значение?   -  person www.admiraalit.nl    schedule 16.11.2015


Ответы (2)


Спасибо всем, я узнал, что просто изменение контекста селекторов заработало, в частности это:

$("thead tr th", this).each(function(i, v){
    console.info($(this));
    header[i] = $(this).text();
});

Полный код выглядит следующим образом. Что он делает, так это отправляет данные таблицы в скрытые поля формы, которые затем можно отправить через AJAX в класс Excel, который я также написал:

Страницы формы и таблицы выглядят следующим образом:

/**
 * Created by PhpStorm.
 * User: james.stoddern
 * Date: 16/11/2015
 * Time: 15:37
 */
error_reporting(E_ERROR);
ini_set('display_errors', 1);

////////////////////////////////////////
//Standard Reporting, Database and Excel Class stuff
require_once( $_SERVER['DOCUMENT_ROOT'] . "/common/lib/AJAX_PDO_database_connections.php" );
require_once( $_SERVER['DOCUMENT_ROOT'] . "/common/classes/classes.misc/excel_class.php" );
$excel_helper           = new Excel($dbpdo);
if (isset($_REQUEST['export'])) {
    $report_name    = $_REQUEST["report_name"];
    $headers        = $_REQUEST["header"];
    $rows           = $_REQUEST["rows"];
    $footer         = $_REQUEST["footer"];
    $excel_helper->exportExcel($report_name, $headers, $rows, $footer);
    exit();
}

?>
<script src="/res/js/jquery191.js"></script>
<script src="/tests/excelify.js"></script>

<table id="tableid">
    <thead>
    <tr>
    <th>Order</th>
    <th>User</th>
    <th>Product</th>
    <th>Total</th>
    </tr>
    </thead>

    <tbody>
    <tr>
        <td data-format="bold">3145</td>
        <td data-format="bold underline">James</td>
        <td>Pens</td>
        <td>230.55</td>
    </tr>

    <tr>
        <td>31435</td>
        <td>Rich</td>
        <td>Bags</td>
        <td>3320.55</td>
    </tr>

    <tr>
        <td>4145</td>
        <td>Dobby</td>
        <td>baloons</td>
        <td>30.55</td>
    </tr>
    </tbody>

    <tfoot>
    <tr>
        <td></td>
        <td></td>
        <td>TOTAL</td>
        <td>9999.99</td>
    </tr>
    </tfoot>

</table>

<form id="convert_form" name="F1" method="post" action="/tests/convert_table_to_array.php">
    <input type="hidden" id="report_name" name="report_name" value="Test Report">
    <input type="hidden" id="header" name="header" value="" />
    <input type="hidden" id="rows" name="rows" value="" />
    <input type="hidden" id="footer" name="footer" value="" />
    <input type="hidden" name="export" id="export" value="Export to Excel">
</form>

<button id="convert" onclick="convertTableToExcel()">Convert</button>
<script>

    function convertTableToExcel() {
        jQuery("#tableid").excelify("convert_form");
    }
</script>

И файл плагина выглядит следующим образом:

(function ( $ ) {

$.fn.excelify = function(output_form) {
    //Build the Header Rows
    var header = Array();

    $("thead tr th", this).each(function(i, v){
        console.info($(this));
        header[i] = $(this).text();
    });

    //Write the Footer JSON data to a hidden field on the calling page called "header"
    $("#header").val(JSON.stringify(header));
    //console.info(JSON.stringify(header));

    //build the Data Rows
    var data = Array();
    $("tbody tr", this).each(function(i, v){
        data[i] = Array();
        $(this).children('td').each(function(ii, vv){

            //if the data is delimited with a pipe, then there is also formatting information, such as Bold
            if($(this).data('format')) {
                data_format = $(this).data('format');
            } else {
                data_format = "";
            }

            value = $(this).text();
            data[i][ii] = data_format + "|" + value;
        });
    });

    //Write the Tbody JSON data to a hidden field on the calling page called "rows"
    $("#rows").val(JSON.stringify(data));

    //Build the Footer Rows
    var footer = Array();
    $("tfoot tr td", this).each(function(i, v){
        footer[i] = $(this).text();
    });

    //Write the Footer JSON data to a hidden field on the calling page called "footer"
    $("#footer").val(JSON.stringify(footer));


    //Submit the form
    $("#" + output_form).submit();
};

}(jQuery));

Я написал на PHP класс excel, который может экспортировать все данные таблицы в формат Excel:

////////////////////////////////////////
require_once( $_SERVER['DOCUMENT_ROOT'] . "/common/lib/PHPExcel.php" );
class Excel
{
    private $pdo;
    private $excel;
    private $title;
    private $lastDataRow;

    /////////////////////////////////////////////////////////////
    function __construct($dbpdo)
    {
        //Grab the DB
        $this->pdo = $dbpdo;
        $this->_initialise();
    }


    ////////////////////////////////////////////////////////////////
    /**
     * Instantiate the PHPExcel class
     */
    private function _initialise() {
        $this->excel = new PHPExcel();
    }


    ///////////////////////////////////////////////////////
    /**
     * Export the Excel sheet
     * @param $header
     * @param $rows
     * @param $footer
     */
    public function exportExcel($title, $header, $rows, $footer) {
        $this->title = $title;

        // Set spreadsheet properties
        $this->excel->getProperties()->setCreator("James Inc Reporting");
        $this->excel->getProperties()->setLastModifiedBy("James Inc Reporting");
        $this->excel->getProperties()->setTitle($title);
        $this->excel->getProperties()->setSubject($title);
        $this->excel->getProperties()->setDescription($title);

        // Use first worksheet
        $this->excel->setActiveSheetIndex(0);

        // Set up title
        $this->excel->getActiveSheet()->SetCellValue('A1', $title);
        $this->excel->getActiveSheet()->getStyle('A1')->getFont()->setBold(true);
        $this->excel->getActiveSheet()->getStyle('A1')->getFont()->setSize(16);
        $this->excel->getActiveSheet()->getStyle('A1')->getFont()->setUnderline(true);

        // decode the JSON arrays
        $header     = json_decode($header);
        $footer     = json_decode($footer);
        $rows       = json_decode($rows);

        //render the ouutput
        $this->_renderHeader($header);
        $this->_renderRows($header, $rows);
        $this->_renderFooter($footer, $lastrow);

        //send to the browser
        $this->_output();
    }


    /////////////////////////////////////////////////////
    /**
     * Render the Header Rows
     */
    private function _renderHeader($header) {
        $colNumber = 0;
        foreach($header as $cell) {
            $this->excel->getActiveSheet()->getStyleByColumnAndRow($colNumber,3)->getFont()->setUnderline(true);
            $this->excel->getActiveSheet()->getStyleByColumnAndRow($colNumber,3)->getFont()->setBold(true);
            //$this->excel->getActiveSheet()->getColumnDimension($colNumber)->setAutoSize(true);
            $this->excel->getActiveSheet()->setCellValueByColumnAndRow($colNumber, 3, $cell);
            $colNumber++;
        }
    }


    ////////////////////////////////////////////////////////////
    /**
     * Render the Data Rows
     */
    private function _renderRows($header, $rows) {
        $startRow = 4;
        $rowNumber = 0;

        foreach($rows as $row) {
            $colNumber = 0;
            foreach($row as $key => $value) {

                //If the value is a pipe delimited string, then the first element contains formatting information
                if(preg_match("/^|/", $value)) {
                    $arr_data = explode("|", $value);
                    $data = $arr_data[1];
                    $format = $arr_data[0];

                    //bold
                    if(preg_match("/bold/", $format)) {
                        $this->excel->getActiveSheet()->getStyleByColumnAndRow($colNumber, $startRow + $rowNumber)->getFont()->setBold(true);
                    }

                    //underline
                    if(preg_match("/underline/", $format)) {
                        $this->excel->getActiveSheet()->getStyleByColumnAndRow($colNumber, $startRow + $rowNumber)->getFont()->setUnderline(true);
                    }
                } else {
                    //else, the values are just plain text values
                    $data = $value;
                }

                if($data > 0) {
                    $this->excel->getActiveSheet()->getStyleByColumnAndRow($colNumber,$startRow + $rowNumber)->getNumberFormat()->setFormatCode('#,##0.000');
                }



                $this->excel->getActiveSheet()->setCellValueByColumnAndRow($colNumber, $startRow + $rowNumber, $data);

                $colNumber++;
            }
            $rowNumber++;
        }
        $this->lastDataRow = $rowNumber + $startRow;
    }



    ////////////////////////////////////////////////////////
    /**
     * Render the Footer Rows
     */
    private function _renderFooter($footer, $lastrow) {
        $colNumber = 0;
        foreach($footer as $cell) {
            if($cell > 0) {
                $this->excel->getActiveSheet()->getStyleByColumnAndRow($colNumber, $this->lastDataRow+1)->getNumberFormat()->setFormatCode('#,##0.000');
            }
            $this->excel->getActiveSheet()->getStyleByColumnAndRow($colNumber, $this->lastDataRow+1)->getFont()->setUnderline(true);
            $this->excel->getActiveSheet()->getStyleByColumnAndRow($colNumber, $this->lastDataRow+1)->getFont()->setBold(true);
            $this->excel->getActiveSheet()->setCellValueByColumnAndRow($colNumber, $this->lastDataRow+1, $cell);
            $colNumber++;
        }
    }

    //////////////////////////////////////////////////////////
    /**
     * Output the file and redirect in the browser to open immediately
     */
    private function _output() {
        $objWriter2007 = PHPExcel_IOFactory::createWriter($this->excel, 'Excel2007');

        // set headers to redirect output to client browser as a file download
        header('Content-Type: application/vnd.openXMLformats-officedocument.spreadsheetml.sheet');
        header('Content-Disposition: attachment;filename="' . $this->title . '.xlsx"');
        header('Cache-Control: max-age=0');
        header('Content-Encoding: UTF-8');

        //-----Output the file to the browser-----
        $objWriter2007->save('php://output');  //push out to the client browser
    }
}

Теперь он работает нормально. Пожалуйста, не стесняйтесь использовать, если вы найдете это полезным. Идея состоит в том, что я могу генерировать множество отчетов и добавлять функцию преобразования Excel в одну строку.

Спасибо за вашу помощь, это привело меня на правильный путь.

Очень признателен.

Джеймс

person James Stoddern    schedule 16.11.2015
comment
Спасибо, что поделились этим и разместили свой код для использования. - person Karl Gjertsen; 17.11.2015

Я думаю, это то, что вы хотите:

        $.fn.excelify = function () {
            //Build the Header Rows
            var header = Array();
            var table = this[0];
            var tableid = this.attr("id");
            jQuery("#" + tableid + " tr th").each(function (i, v) {
                header[i] = jQuery(this).text();
            });
            ... etc.
person www.admiraalit.nl    schedule 16.11.2015