FPDF chinese encode - pdf-generation
I am using FPDF to generate order invoice to customer, so far everything is working fine, except of some of our item name are mixed with Chinese text, and the output is somehow becoming alien's wording, as attached screenshot:
Script to generate PDF invoice:
<?php
require('fpdf.php');
//function hex2dec
//returns an associative array (keys: R,G,B) from a hex html code (e.g. #3FE5AA)
function hex2dec($couleur = "#000000"){
$R = substr($couleur, 1, 2);
$rouge = hexdec($R);
$V = substr($couleur, 3, 2);
$vert = hexdec($V);
$B = substr($couleur, 5, 2);
$bleu = hexdec($B);
$tbl_couleur = array();
$tbl_couleur['R']=$rouge;
$tbl_couleur['G']=$vert;
$tbl_couleur['B']=$bleu;
return $tbl_couleur;
}
//conversion pixel -> millimeter in 72 dpi
function px2mm($px){
return $px*25.4/72;
}
function txtentities($html){
$trans = get_html_translation_table(HTML_ENTITIES);
$trans = array_flip($trans);
return strtr($html, $trans);
}
class PDF extends FPDF
{
//variables of html parser
protected $B;
protected $I;
protected $U;
protected $HREF;
protected $fontList;
protected $issetfont;
protected $issetcolor;
function __construct($orientation='P', $unit='mm', $format='A4')
{
//Call parent constructor
parent::__construct($orientation,$unit,$format);
//Initialization
$this->B=0;
$this->I=0;
$this->U=0;
$this->HREF='';
$this->tableborder=0;
$this->tdbegin=false;
$this->tdwidth=0;
$this->tdheight=0;
$this->tdalign="L";
$this->tdbgcolor=false;
$this->oldx=0;
$this->oldy=0;
$this->fontlist=array("arial","times","courier","helvetica","symbol");
$this->issetfont=false;
$this->issetcolor=false;
}
//////////////////////////////////////
//html parser
function WriteHTML($html)
{
$html=strip_tags($html,"<b><u><i><a><img><p><br><strong><em><font><tr><blockquote><hr><td><tr><table><sup>"); //remove all unsupported tags
$html=str_replace("\n",'',$html); //replace carriage returns with spaces
$html=str_replace("\t",'',$html); //replace carriage returns with spaces
$a=preg_split('/<(.*)>/U',$html,-1,PREG_SPLIT_DELIM_CAPTURE); //explode the string
foreach($a as $i=>$e)
{
if($i%2==0)
{
//Text
if($this->HREF)
$this->PutLink($this->HREF,$e);
elseif($this->tdbegin) {
if(trim($e)!='' && $e!=" ") {
$this->Cell($this->tdwidth,$this->tdheight,$e,$this->tableborder,'',$this->tdalign,$this->tdbgcolor);
}
elseif($e==" ") {
$this->Cell($this->tdwidth,$this->tdheight,'',$this->tableborder,'',$this->tdalign,$this->tdbgcolor);
}
}
else
$this->Write(5,stripslashes(txtentities($e)));
}
else
{
//Tag
if($e[0]=='/')
$this->CloseTag(strtoupper(substr($e,1)));
else
{
//Extract attributes
$a2=explode(' ',$e);
$tag=strtoupper(array_shift($a2));
$attr=array();
foreach($a2 as $v)
{
if(preg_match('/([^=]*)=["\']?([^"\']*)/',$v,$a3))
$attr[strtoupper($a3[1])]=$a3[2];
}
$this->OpenTag($tag,$attr);
}
}
}
}
function OpenTag($tag, $attr)
{
//Opening tag
switch($tag){
case 'SUP':
if( !empty($attr['SUP']) ) {
//Set current font to 6pt
$this->SetFont('','',6);
//Start 125cm plus width of cell to the right of left margin
//Superscript "1"
$this->Cell(2,2,$attr['SUP'],0,0,'L');
}
break;
case 'TABLE': // TABLE-BEGIN
if( !empty($attr['BORDER']) ) $this->tableborder=$attr['BORDER'];
else $this->tableborder=0;
break;
case 'TR': //TR-BEGIN
break;
case 'TD': // TD-BEGIN
if( !empty($attr['WIDTH']) ) $this->tdwidth=($attr['WIDTH']/4);
else $this->tdwidth=40; // Set to your own width if you need bigger fixed cells
if( !empty($attr['HEIGHT']) ) $this->tdheight=($attr['HEIGHT']/6);
else $this->tdheight=6; // Set to your own height if you need bigger fixed cells
if( !empty($attr['ALIGN']) ) {
$align=$attr['ALIGN'];
if($align=='LEFT') $this->tdalign='L';
if($align=='CENTER') $this->tdalign='C';
if($align=='RIGHT') $this->tdalign='R';
}
else $this->tdalign='R'; // Set to your own
if( !empty($attr['BGCOLOR']) ) {
$coul=hex2dec($attr['BGCOLOR']);
$this->SetFillColor($coul['R'],$coul['G'],$coul['B']);
$this->tdbgcolor=true;
}
$this->tdbegin=true;
break;
case 'HR':
if( !empty($attr['WIDTH']) )
$Width = $attr['WIDTH'];
else
$Width = $this->w - $this->lMargin-$this->rMargin;
$x = $this->GetX();
$y = $this->GetY();
$this->SetLineWidth(0.2);
$this->Line($x,$y,$x+$Width,$y);
$this->SetLineWidth(0.2);
$this->Ln(1);
break;
case 'STRONG':
$this->SetStyle('B',true);
break;
case 'EM':
$this->SetStyle('I',true);
break;
case 'B':
case 'I':
case 'U':
$this->SetStyle($tag,true);
break;
case 'A':
$this->HREF=$attr['HREF'];
break;
case 'IMG':
if(isset($attr['SRC']) && (isset($attr['WIDTH']) || isset($attr['HEIGHT']))) {
if(!isset($attr['WIDTH']))
$attr['WIDTH'] = 0;
if(!isset($attr['HEIGHT']))
$attr['HEIGHT'] = 0;
$this->Image($attr['SRC'], $this->GetX(), $this->GetY(), px2mm($attr['WIDTH']), px2mm($attr['HEIGHT']));
}
break;
case 'BLOCKQUOTE':
case 'BR':
$this->Ln(5);
break;
case 'P':
$this->Ln(10);
break;
case 'FONT':
if (isset($attr['COLOR']) && $attr['COLOR']!='') {
$coul=hex2dec($attr['COLOR']);
$this->SetTextColor($coul['R'],$coul['G'],$coul['B']);
$this->issetcolor=true;
}
if (isset($attr['FACE']) && in_array(strtolower($attr['FACE']), $this->fontlist)) {
$this->SetFont(strtolower($attr['FACE']));
$this->issetfont=true;
}
if (isset($attr['FACE']) && in_array(strtolower($attr['FACE']), $this->fontlist) && isset($attr['SIZE']) && $attr['SIZE']!='') {
$this->SetFont(strtolower($attr['FACE']),'',$attr['SIZE']);
$this->issetfont=true;
}
break;
}
}
function CloseTag($tag)
{
//Closing tag
if($tag=='SUP') {
}
if($tag=='TD') { // TD-END
$this->tdbegin=false;
$this->tdwidth=0;
$this->tdheight=0;
$this->tdalign="L";
$this->tdbgcolor=false;
}
if($tag=='TR') { // TR-END
$this->Ln();
}
if($tag=='TABLE') { // TABLE-END
$this->tableborder=0;
}
if($tag=='STRONG')
$tag='B';
if($tag=='EM')
$tag='I';
if($tag=='B' || $tag=='I' || $tag=='U')
$this->SetStyle($tag,false);
if($tag=='A')
$this->HREF='';
if($tag=='FONT'){
if ($this->issetcolor==true) {
$this->SetTextColor(0);
}
if ($this->issetfont) {
$this->SetFont('arial');
$this->issetfont=false;
}
}
}
function SetStyle($tag, $enable)
{
//Modify style and select corresponding font
$this->$tag+=($enable ? 1 : -1);
$style='';
foreach(array('B','I','U') as $s) {
if($this->$s>0)
$style.=$s;
}
$this->SetFont('',$style);
}
function PutLink($URL, $txt)
{
//Put a hyperlink
$this->SetTextColor(0,0,255);
$this->SetStyle('U',true);
$this->Write(5,$txt,$URL);
$this->SetStyle('U',false);
$this->SetTextColor(0);
}
// Page header
function Header()
{
// Logo
$this->Image(logo-mono.jpg',10,10,30);
$this->SetFont('Arial','B',15);
$this->Cell(138);
$this->Cell(70,5,'TAX INVOICE',0,0,'C');
$this->Ln(12);
// Company Header
$this->SetFont('Arial','B',9);
$this->Cell(0,5,'ABC COMPANY (1063511-D)',0,0,'L');
$this->Ln(0);
// Line break
$this->Ln(15);
}
// Page footer
function Footer()
{
// Position at 1.5 cm from bottom
$this->SetY(-15);
// Arial italic 8
$this->SetFont('Arial','I',8);
// Page number
$this->Cell(0,10,'Page '.$this->PageNo().'/{nb}',0,0,'C');
}
}
//Fetching specific order data and prepare an invoice
$invoice = $buyer->get_completed_transaction(
filter_var('1466404785-0J2XQR',FILTER_SANITIZE_STRING),
filter_var('T108869482600',FILTER_SANITIZE_STRING),
filter_var('LG6j3DYQbnylAFdaSdzcx5J0SYo=',FILTER_SANITIZE_STRING),
$mysqli
);
if($invoice !== FALSE){
//Checkout with BRP+CASH or CASH only, 2=BRP+CASH.
$checkout_method = $invoice->checkout_method;
//GENERATE INVOICE
$shipping_addr_1 = $invoice->shipping_address.',';
$shipping_addr_2 = $invoice->shipping_postcode.' '.$invoice->shipping_city.',';
$shipping_addr_3 = $invoice->shipping_province.' '.$invoice->shipping_country.'.';
// Instanciation of inherited class
$pdf = new PDF('P', 'mm', 'A4');
$pdf->AliasNbPages();
$pdf->AddPage();
$pdf->SetFont('Arial','B',9);
$pdf->setFillColor(230,230,230);
$pdf->Cell(50,5,'BILL TO',1,0,'L',1);
$pdf->Ln(3);
//
$pdf->SetFont('Arial','',9);
$pdf->Cell(0,15,strtoupper($invoice->recipient_name),0,0,'L');
$pdf->SetFont('Arial','B',8);
$pdf->Text(146,58,'DATE:');
$pdf->Text(146,63,'INVOICE #');
$pdf->Text(146,68,'CUSTOMER ID');
$pdf->SetFont('Arial','',8);
$pdf->Text(170,58,date('d/m/Y'));
$pdf->Text(170,63,$invoice->order_num);
$pdf->Ln(5);
$pdf->SetFont('Arial','',8);
$pdf->Cell(0,15,ucwords(strtolower($shipping_addr_1)),0,0,'L');
$pdf->Ln(5);
$pdf->Cell(0,15,ucwords(strtolower($shipping_addr_2)),0,0,'L');
$pdf->Ln(5);
$pdf->Cell(0,15,ucwords(strtolower($shipping_addr_3)),0,0,'L');
//
/*
$pdf->Ln(5);
$pdf->SetFont('Arial','B',8);
$pdf->Cell(10,25,'Tel:');
$pdf->SetFont('Arial','',8);
$pdf->Cell(0,25,$invoice->phone);
//
$pdf->Ln(5);
$pdf->SetFont('Arial','B',8);
$pdf->Cell(10,25,'Email:');
$pdf->SetFont('Arial','',8);
$pdf->Cell(118,25,$invoice->email);
*/
//
$pdf->Ln(14);
$pdf->SetFont('Arial','',8);
$html = '
<table border="1">
<tr>
<td width="30" height="30" bgcolor="#dddddd" align="left">No</td>
<td width="90" height="30" bgcolor="#dddddd" align="left">Item Code</td>
<td width="380" height="30" bgcolor="#dddddd" align="left">Descriptions</td>
<td width="40" height="30" bgcolor="#dddddd">Qty</td>
<td width="100" height="30" bgcolor="#dddddd">Price/Unit</td>
<td width="120" height="30" bgcolor="#dddddd">Amount</td>
</tr>';
$i = 1;
$shipping_rate = SHIPPING_RATE_ALL;
$total_payment = 0;
//Loop order items
$items = unserialize($invoice->cart_item);
foreach($items as $item){
//$keys = array_keys($item);
//$matches = preg_grep('~^p_alt\-variation\-\d+~i', $keys);
$unit_price = ($checkout_method == 2) ? ($item['p_price']/2) : $item['p_price'];
$subtotal = ($checkout_method == 2) ? (($item['p_price']/2) * $item['p_qty']) : ($item['p_price'] * $item['p_qty']);
$html .= '
<tr>
<td width="30" height="30" align="left">'.$i.'</td>
<td width="90" height="30" align="left">'.$item['p_code'].'</td>
<td width="380" height="30" align="left">'.$item['p_name'].'</td>
<td width="40" height="30">'.$item['p_qty'].'</td>
<td width="100" height="30">'.number_format($unit_price, 2, '.', ',').'</td>
<td width="120" height="30">'.number_format($subtotal, 2, '.', ',').'</td>
</tr>';
$i++;
$gross_payment += $subtotal;
}
//End Loop
$html .= '
<tr>
<td width="30" height="30"> </td>
<td width="90" height="30"> </td>
<td width="380" height="30"> </td>
<td width="40" height="30"> </td>
<td width="100" height="30"> </td>
<td width="120" height="30"> </td>
</tr>
<tr>
<td width="30" height="30"> </td>
<td width="90" height="30"> </td>
<td width="380" height="30"> </td>
<td width="40" height="30"> </td>
<td width="100" height="30"> </td>
<td width="120" height="30"> </td>
</tr>
</table>';
$pdf->WriteHTML($html);
//
$pdf->Ln(2);
$pdf->SetFont('Arial','',8);
$pdf->Cell(156,5,'Subtotal',0,0,'R');
$pdf->Cell(8,5,'$',0,0,'R');
$pdf->Cell(0,5,number_format($gross_payment,2,'.',','),0,1,'R');
$pdf->Cell(0,5,'Thank you for your business',0,0,'L');
$pdf->Cell(-34,5,'Shipping Cost',0,0,'R');
$pdf->Cell(8,5,'$',0,0,'R');
$pdf->Cell(0,5,number_format($shipping_rate,2,'.',','),0,1,'R');
if($checkout_method == 2){
$pdf->Cell(156,5,'BRP Consume',0,0,'R');
$pdf->Cell(8,5,'-',0,0,'R');
$pdf->Cell(0,5,number_format($invoice->total_points_consume,0,'.',','),0,1,'R');
}
$pdf->Ln(1);
$pdf->Cell(125,0,'',0,0,'R');
$pdf->Cell(65,0,'',1,0,'R');
$pdf->Ln(1);
$pdf->SetFont('Arial','B',8);
$pdf->Cell(156,10,'Total Including GST',0,0,'R');
$pdf->Cell(8,10,'$',0,0,'R',1);
$pdf->Cell(0,10,number_format($gst+$gross_payment+$shipping_rate,2,'.',','),0,1,'R',1);
$pdf->Ln(1);
//GST calculation
$gst = round((($gross_payment+$shipping_rate)*6.00)/100, 1);
$pdf->SetFont('Arial','',8);
$pdf->SetTextColor('88','88','88');
$pdf->Cell(156,5,'GST 6%',0,0,'R');
$pdf->Cell(8,5,'$',0,0,'R');
$pdf->Cell(0,5,number_format($gst,2,'.',','),0,1,'R');
$pdf->Ln(1);
//
$pdf->Ln(10);
//$pdf->WriteHTML('<HR>');
$pdf->SetFont('Arial','B',8);
$pdf->Cell(90,5,'ABC COMPANY',0,0,'L',0);
$pdf->Ln(20);
$pdf->Cell(50,0,'',1,1,'L',0);
$pdf->Ln(1);
$pdf->SetFont('Arial','BI',8);
$pdf->Cell(90,5,'Authorised Signature',0,0,'L',0);
$path = '/invoice/';
$file = $invoice->order_num.'.pdf';
$pdf->Output();
}
?>
I've been look for the solution around and tried with tFPDF, I get error with
Fatal error: Call to undefined method tFPDF::WriteHTML() in C:\pathto\create_invoice_test.php on line 448
I have no idea of how to implement it into current scripts, I need workaround to solve this issue.
Related
Using AJAX to filter all data in a column in ASC/DESC order
I'm using CodeIgniter to retrieve a count of data in my table with thier respective agent name. I'm doing this by using the following statement: $sql = SELECT count(*) AS cnt FROM table 1 t LEFT JOIN user_table c ON t.agent_id = c.id GROUP BY COALESCE(t.agent_id, 0), c.display_name ORDER BY c.display_name IS NULL, c.display_name; $query = $this->db->query($sql); return $query; And this has given me the following output giving the table data from A-Z in terms of the name: enter image description here Now I want to be able to filter this data in ASC and DESC order when I click on thier headings of the table. Here is the code I have for my table: <thead> <tr> <th><div onclick=//Some method>Agent</div></th> <th><div onclick=//Some method>Count</div></th> </tr> </thead> <?php if(isset($agent_count) && count($agent_count) > 0) { foreach($agent_count as $row ){ ?> <tr> <td><?= $row->name ?></td> <td><?= $row->cnt ?></td> </tr> <?php } } ?> So here to order the data, I'm assuming an AJAX call needs to be made to order the data in DESC if it already is ASC or to ASC if it is already DESC. Also if I click on the count heading to get that data in DESC order, then the Agent column should also sort accordingly to its respective data.
You can achieve the same using javascript. There is no need to do another ajax call. You can just get the data once from the server and then using javascript to sort the table. Source: Sort a HTML table on header click function sortTable(n) { var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0; table = document.getElementById("myTable"); switching = true; //Set the sorting direction to ascending: dir = "asc"; /*Make a loop that will continue until no switching has been done:*/ while (switching) { //start by saying: no switching is done: switching = false; rows = table.rows; /*Loop through all table rows (except the first, which contains table headers):*/ for (i = 1; i < (rows.length - 1); i++) { //start by saying there should be no switching: shouldSwitch = false; /*Get the two elements you want to compare, one from current row and one from the next:*/ x = rows[i].getElementsByTagName("TD")[n]; y = rows[i + 1].getElementsByTagName("TD")[n]; /*check if the two rows should switch place, based on the direction, asc or desc:*/ if (dir == "asc") { if (x.innerHTML.match(/^-?\d+$/) && y.innerHTML.match(/^-?\d+$/)) { if (Number(x.innerHTML) > Number(y.innerHTML)) { //if so, mark as a switch and break the loop: shouldSwitch = true; break; } } else if (x.innerHTML.match(/^\d+\.\d+$/) && y.innerHTML.match(/^\d+\.\d+$/)) { if (Number(x.innerHTML) > Number(y.innerHTML)) { //if so, mark as a switch and break the loop: shouldSwitch = true; break; } } else { if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) { //if so, mark as a switch and break the loop: shouldSwitch = true; break; } } } else if (dir == "desc") { if (x.innerHTML.match(/^-?\d+$/) && y.innerHTML.match(/^-?\d+$/)) { if (Number(x.innerHTML) < Number(y.innerHTML)) { //if so, mark as a switch and break the loop: shouldSwitch = true; break; } } else if (x.innerHTML.match(/^\d+\.\d+$/) && y.innerHTML.match(/^\d+\.\d+$/)) { if (Number(x.innerHTML) < Number(y.innerHTML)) { //if so, mark as a switch and break the loop: shouldSwitch = true; break; } } else { if (x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase()) { //if so, mark as a switch and break the loop: shouldSwitch = true; break; } } } } if (shouldSwitch) { /*If a switch has been marked, make the switch and mark that a switch has been done:*/ rows[i].parentNode.insertBefore(rows[i + 1], rows[i]); switching = true; //Each time a switch is done, increase this count by 1: switchcount++; } else { /*If no switching has been done AND the direction is "asc", set the direction to "desc" and run the while loop again.*/ if (switchcount == 0 && dir == "asc") { dir = "desc"; switching = true; } } } } table { border-spacing: 0; width: 100%; border: 1px solid #ddd; } th { cursor: pointer; } th, td { text-align: left; padding: 16px; } tr:nth-child(even) { background-color: #f2f2f2 } <!DOCTYPE html> <html> <head> <title>Sort a HTML Table Alphabetically</title> </head> <body> <table id="myTable"> <tr> <!--When a header is clicked, run the sortTable function, with a parameter, 0 for sorting by names, 1 for sorting by country:--> <th onclick="sortTable(0)">Name</th> <th onclick="sortTable(1)">Country</th> <th onclick="sortTable(2)">Count</th> <th onclick="sortTable(3)">Rating</th> </tr> <tr> <td>Berglunds snabbkop</td> <td>Sweden</td> <td>5</td> <td>4.5</td> </tr> <tr> <td>North/South</td> <td>UK</td> <td>3</td> <td>3</td> </tr> <tr> <td>Alfreds Futterkiste</td> <td>Germany</td> <td>1</td> <td>2.8</td> </tr> <tr> <td>Koniglich Essen</td> <td>Germany</td> <td>78</td> <td>0.9</td> </tr> <tr> <td>Magazzini Alimentari Riuniti</td> <td>Italy</td> <td>5</td> <td>4.5</td> </tr> <tr> <td>Paris specialites</td> <td>France</td> <td>7</td> <td>1.3</td> </tr> <tr> <td>Island Trading</td> <td>UK</td> <td>0</td> <td>1.2</td> </tr> <tr> <td>Laughing Bacchus Winecellars</td> <td>Canada</td> <td>2</td> <td>3.5</td> </tr> </table> </body> </html>
Scrollx hide search inputs
I have a little problem. When adding my table the element "scrollX": true, the search entries disappear. CODE: JAVASCRIPT function parametrosTabla6(tabla) { var tabla2 = $(tabla).DataTable({ 'paging': true, 'searching': true, 'ordering': true, 'orderCellsTop': true, 'order': [ [0, 'desc'] ], "scrollX": true, 'columnDefs': [ { 'responsivePriority': 1, 'targets': 0 }, { 'responsivePriority': 2, 'targets': -1 }, { "className": "dt-center", "targets": "_all" } ], 'responsive': true, }); var len = $('#datos thead tr:eq(1) th').length; $('#datos tfoot:eq(0) th').each(function (i, e) { var title = $(this).text(); if (i == len - 1) { } else { $(this).html('<input style="width:100%" class="form-control" data-column="' + (i + 1) + '" type="text" placeholder="' + title + '" />'); } $('input', this).on('keyup change', function () { if (tabla2.column(i).search() !== this.value) { tabla2.column(i).search(this.value).draw(); } }); }); } HTML/CSS/PHP <table id="datos" class="table table-hover display drtresponsive nowrap" width="100%"> <thead> <th>Nº Pedido</th> <th>Cliente</th> <th>Nº Telefono (fijo-movil)</th> <th>Fecha Venta</th> <th>Correo Enviado</th> <th>Estado Pago</th> <th>Expedicion</th> <th>Fecha Envio</th> <th>Fecha Entrega</th> <th>Recibido</th> <th>Anulado</th> <th>Usuario Venta</th> <th>Ultimo usuario editado</th> <th>Acciones Disponibles</th> </thead> <tfoot style="display: table-header-group"> <tr> <th>Nº Pedido</th> <th>Cliente</th> <th>Nº Telefono (fijo-movil)</th> <th>Fecha Venta</th> <th>Correo Enviado</th> <th>Estado Pago</th> <th>Expedicion</th> <th>Fecha Envio</th> <th>Fecha Entrega</th> <th>Recibido</th> <th>Anulado</th> <th>Usuario Venta</th> <th>Ultimo usuario editado</th> <th>Acciones Disponibles</th> </tr> </tfoot> <tbody> <?php if (isset($result)) { if ($result->num_rows > 0) { while ($row = $result->fetch_assoc()) { switch ($row['recibido']) { case 0: $row['recibido'] = "NO"; break; case 1: $row['recibido'] = "SI"; break; } switch ($row['correo_confirmacion']) { case 0: $row['correo_confirmacion'] = "NO"; break; case 1: $row['correo_confirmacion'] = "SI"; break; } switch ($row['factura']) { case 0: $row['factura'] = "NO"; break; case 1: $row['factura'] = "SI"; break; } switch ($row['anulado']) { case 0: $row['anulado'] = "NO"; break; case 1: $row['anulado'] = "SI"; break; } require 'mod/tabla_facturas.php'; } } else { echo "<tr>0 results</td>"; } } else { echo "<td colspan='100%'>0 results</td>"; } ?> </tbody> </table>
Here is the answer. You have two options: (The one I have chosen) Put the overflow-x:auto in parent div. Clone the thead and add the inputs. var len = $('#datos thead tr:eq(1) th').length; $('#datos thead tr').clone(true).appendTo('#datos thead'); $('#datos thead tr:eq(1) th').each(function (i, e) { var title = $(this).text(); if (i == len - 1) { } else { $(this).html('<input style="width:100%" type="text" placeholder="' + title + '" />'); } $('input', this).on('keyup change', function () { if (table.column(i).search() !== this.value) { table .column(i) .search(this.value) .draw(); } }); }); Add the orderCellsTop option to the datatable.
Filter records using daterangetime picker
I have a target where I need to filter the data using daterange with time picker. The thing is I need to show the result of my filtered data based on what I selected on the said daterange with time picker I have provided my codes below and my target. Thank you so much in advance. Views: <div class="card-body table-responsive py-3 px-3"> <input type="text" id="demo" name="daterange" value="06/05/2021 - 06/06/2021" style="width:350px;"> <button class="btn btn-success float-right" onclick="add_person()" data-dismiss="modal"><i class="glyphicon glyphicon-plus"></i> Add Person</button> <table id="table_account" class="table table-bordered table-hover" cellspacing="0"> <thead> <tr> <th>First Name</th> <th>Last Name</th> <th>Username</th> <th>Email</th> <th>Mobile</th> <th>Role</th> <th>Status </th> <!-- <th>File </th> --> <th>Added By</th> <th>Date Created</th> <th>Date Updated</th> <th>Updated By</th> <th style="width:100x;">Action</th> </tr> </thead> <tbody> </tbody> </table> </div> </script> <thead> <tr> <th>First Name</th> <th>Last Name</th> <th>Username</th> <th>Email</th> <th>Mobile</th> <th>Role</th> <th>Status </th> <th>Added By</th> <th>Date Created</th> <th>Date Updated</th> <th>Updated By</th> <th style="width:100x;">Action</th> </tr> </thead> <tbody> </tbody> </table> </div> Ajax: <script> // first, put this at the top of your JS code. let dateParams = {} // update this with setting dataParams $('#demo').daterangepicker({ "timePicker": true, "timePicker24Hour": true, "startDate": "06/05/2021", "endDate": "06/06/2021", locale: { format: 'M/DD/YYYY hh:mm A' } }, function(start, end, label) { // set the dateParam obj dateParams = { start: start.format('YYYY-MM-DD hh:mm'), end: end.format('YYYY-MM-DD hh:mm') } console.log('New date range selected: ' + start.format('YYYY-MM-DD hh:mm') + ' to ' + end.format('YYYY-MM-DD hh:mm') + ' (predefined range: ' + start + + end +')'); }); $(document).ready(function() { //datatables table = $('#table_account').DataTable({ dom: 'lBfrtip', buttons: [ 'print', 'csv', 'copy', 'excel', 'pdfHtml5' ], "processing": false, //Feature control the processing indicator. "serverSide": true, //Feature control DataTables' server-side processing mode. "order": [], //Initial no order. // Load data for the table's content from an Ajax source "ajax": { "url": "<?php echo site_url('profile/ajax_list')?>", "type": "POST", "data": function (dateParams) { return $.extend( { "start": dateParams.start, "end": dateParams.end,}, dateParams, { }); }, }, //Set column definition initialization properties. "columnDefs": [ { "targets": [ 0 ], //first column "orderable": false, //set not orderable }, { "targets": [ -1 ], //last column "orderable": false, //set not orderable }, ], }); }); setInterval( function () { table.ajax.reload(null,false); }, 1000); </script> Controller: public function ajax_list() { $list = $this->profiles->get_datatables(); $data = array(); $no = $_POST['start']; foreach ($list as $person) { $no++; $row = array(); $row[] = $person->firstname; $row[] = $person->lastname; $row[] = $person->username; $row[] = $person->email; $row[] = $person->mobile; $row[] = $person->role; $row[] = $person->status; $row[] = $person->addedBy; $row[] = $person->dateCreated; $row[] = $person->updatedBy; $row[] = $person->dateUpdated; //add html for action $row[] = '<a class="btn btn-sm btn-primary" href="javascript:void(0)" title="Edit" onclick="edit_person('."'".$person->userID."'".')"><i class="glyphicon glyphicon-pencil"></i> Edit</a>'; $data[] = $row; } $output = array( "draw" => $_POST['draw'], "recordsTotal" => $this->profiles->count_all(), "recordsFiltered" => $this->profiles->count_filtered(), "data" => $data, ); //output to json format echo json_encode($output); } Model: var $table = 'users'; var $column_order = array(null,'userID','firstname','lastname','username','email','mobile','addedBy','dateCreated'); var $order = array('userID' => 'desc'); var $column_search = array('email','firstname','lastname','username','email','mobile','dateCreated'); //set column field database for datatable orderable //set column field database for datatable searchable just firstname , lastname , address are searchable var $order = array('id' => 'desc'); // default order private function _get_datatables_query() { if($this->input->post('daterange')){ $this->db->where('dateCreated >=', $this->input->post('start')); $this->db->where('dateCreated <=', $this->input->post('end')); } // $this->input->post('start'); // YYYY-mm-dd // $this->input->post('end'); // YYYY-mm-dd $this->db->from($this->table); $i = 0; foreach ($this->column_search as $item) // loop column { if($_POST['search']['value']) // if datatable send POST for search { if($i===0) // first loop { $this->db->group_start(); // open bracket. query Where with OR clause better with bracket. because maybe can combine with other WHERE with AND. $this->db->like($item, $_POST['search']['value']); } else { $this->db->or_like($item, $_POST['search']['value']); } if(count($this->column_search) - 1 == $i) //last loop $this->db->group_end(); //close bracket } $i++; } if(isset($_POST['order'])) // here order processing { $this->db->order_by($this->column_order[$_POST['order']['0']['column']], $_POST['order']['0']['dir']); } else if(isset($this->order)) { $order = $this->order; $this->db->order_by(key($order), $order[key($order)]); } } function get_datatables() { $this->_get_datatables_query(); if($_POST['length'] != -1) $this->db->limit($_POST['length'], $_POST['start']); $query = $this->db->get(); return $query->result(); }
To connect the calendar with the data output table, edit your daterangepicker initialization: // first, put this at the top of your JS code. let dateParams = {} // update this with setting dataParams $('#demo').daterangepicker({ "timePicker": true, "timePicker24Hour": true, "startDate": "06/05/2021", "endDate": "06/06/2021", locale: { format: 'M/DD hh:mm A' } }, function(start, end, label) { // set the dateParam obj dataParams = { start: start.format('YYYY-MM-DD'), end: end.format('YYYY-MM-DD') } // reload the table table.ajax.reload(); //console.log('New date range selected: ' + start.format('YYYY-MM-DD') + ' to ' + end.format('YYYY-MM-DD') + ' (predefined range: ' + label + ')'); }); Over in your DataTable() setup change your ajax to pass the start and end dates "ajax": { "url": "<?php echo site_url('profile/ajax_list')?>", "type": "POST", "data": function ( d ) { // add this return $.extend( {}, d, { "start": dataParams.start, "end": dataParams.end }); // could also be written: return $.extend( {}, d, dataParams); } } Finally, you'll need to pick this up in your CI app so you can search you DB. $this->input->post('start'); // YYYY-mm-dd $this->input->post('end'); // YYYY-mm-dd Then this is just a nit. Please move <table id="table_account" class="table table-bordered table-hover" cellspacing="0"> to right above the first <thead>. Right now there is the datepicker element in between them. Might not matter, but it should be fixed. https://datatables.net/reference/option/ajax
CI PHPExcel, How to import one multi-sheet xlsx to multiple table in sql database?
As I state in the title, Is it possible to do such thing? May I have the example? Thanks in advance
this is jquery it will be easy to do <!DOCTYPE html> <html> <head> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script> <body> <table id="tbl1" class="table2excel"> <tr> <td>Product</td> <td>Price</td> <td>Available</td> <td>Count</td> </tr> <tr> <td>Bred</td> <td>1</td> <td>2</td> <td>3</td> </tr> <tr> <td>Butter</td> <td>4 </td> <td>5 </td> <td>6 </td> </tr> </table> <hr> <table id="tbl2" class="table2excel"> <tr> <td>Product</td> <td>Price</td> <td>Available</td> <td>Count</td> </tr> <tr> <td>Bred</td> <td>7</td> <td>8</td> <td>9</td> </tr> <tr> <td>Butter</td> <td>14</td> <td>15</td> <td >16</td> </tr> </table> <hr> <table id="tbl3" class="table2excel"> <tr> <td>Product</td> <td>Price</td> <td>Available</td> <td>Count</td> </tr> <tr> <td>Bred</td> <td>7</td> <td>8</td> <td>9</td> </tr> <tr> <td>Butter</td> <td>14</td> <td>15</td> <td >16</td> </tr> </table> <hr> <table id="tbl4" class="table2excel"> <tr> <td>Product</td> <td>Price</td> <td>Available</td> <td>Count</td> </tr> <tr> <td>Bred</td> <td>7</td> <td>8</td> <td>9</td> </tr> <tr> <td>Awss</td> <td>14</td> <td>15</td> <td >16</td> </tr> </table> <button onclick="tablesToExcel(['tbl1','tbl2','tbl3','tbl4'], ['ProductDay1','ProductDay2','Sheet3','Sheet4'], 'TestBook.xls', 'Excel')">Export to Excel</button> <script> var tablesToExcel = (function() { var uri = 'data:application/vnd.ms-excel;base64,' , tmplWorkbookXML = '<?xml version="1.0"?><?mso-application progid="Excel.Sheet"?><Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">' + '<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office"><Author>Axel Richter</Author><Created>{created}</Created></DocumentProperties>' + '<Styles>' + '<Style ss:ID="Currency"><NumberFormat ss:Format="Currency"></NumberFormat></Style>' + '<Style ss:ID="Date"><NumberFormat ss:Format="Medium Date"></NumberFormat></Style>' + '</Styles>' + '{worksheets}</Workbook>' , tmplWorksheetXML = '<Worksheet ss:Name="{nameWS}"><Table>{rows}</Table></Worksheet>' , tmplCellXML = '<Cell{attributeStyleID}{attributeFormula}><Data ss:Type="{nameType}">{data}</Data></Cell>' , base64 = function(s) { return window.btoa(unescape(encodeURIComponent(s))) } , format = function(s, c) { return s.replace(/{(\w+)}/g, function(m, p) { return c[p]; }) } return function(tables, wsnames, wbname, appname) { var ctx = ""; var workbookXML = ""; var worksheetsXML = ""; var rowsXML = ""; for (var i = 0; i < tables.length; i++) { if (!tables[i].nodeType) tables[i] = document.getElementById(tables[i]); for (var j = 0; j < tables[i].rows.length; j++) { rowsXML += '<Row>' for (var k = 0; k < tables[i].rows[j].cells.length; k++) { var dataType = tables[i].rows[j].cells[k].getAttribute("data-type"); var dataStyle = tables[i].rows[j].cells[k].getAttribute("data-style"); var dataValue = tables[i].rows[j].cells[k].getAttribute("data-value"); dataValue = (dataValue)?dataValue:tables[i].rows[j].cells[k].innerHTML; var dataFormula = tables[i].rows[j].cells[k].getAttribute("data-formula"); dataFormula = (dataFormula)?dataFormula:(appname=='Calc' && dataType=='DateTime')?dataValue:null; ctx = { attributeStyleID: (dataStyle=='Currency' || dataStyle=='Date')?' ss:StyleID="'+dataStyle+'"':'' , nameType: (dataType=='Number' || dataType=='DateTime' || dataType=='Boolean' || dataType=='Error')?dataType:'String' , data: (dataFormula)?'':dataValue , attributeFormula: (dataFormula)?' ss:Formula="'+dataFormula+'"':'' }; rowsXML += format(tmplCellXML, ctx); } rowsXML += '</Row>' } ctx = {rows: rowsXML, nameWS: wsnames[i] || 'Sheet' + i}; worksheetsXML += format(tmplWorksheetXML, ctx); rowsXML = ""; } ctx = {created: (new Date()).getTime(), worksheets: worksheetsXML}; workbookXML = format(tmplWorkbookXML, ctx); var link = document.createElement("A"); link.href = uri + base64(workbookXML); link.download = wbname || 'Workbook.xls'; link.target = '_blank'; document.body.appendChild(link); link.click(); document.body.removeChild(link); } })(); </script> </body> </html>
put all PHPExcel-1.8 code in third_party/PHPExcel-1.8 Create libraries/Excel.php as below. this is wrapper on PHPExcel lib. require_once APPPATH . "/third_party/PHPExcel-1.8/Classes/PHPExcel.php"; class Excel extends PHPExcel { public function __construct() { parent::__construct(); } private function parseFile($filePath){ //Create excel reader after determining the file type $inputFileName = $filePath; /** Identify the type of $inputFileName * */ $inputFileType = PHPExcel_IOFactory::identify($inputFileName); /** Create a new Reader of the type that has been identified * */ $objReader = PHPExcel_IOFactory::createReader($inputFileType); /** Set read type to read cell data onl * */ $objReader->setReadDataOnly(true); /** Load $inputFileName to a PHPExcel Object * */ $objPHPExcel = $objReader->load($inputFileName); //Get worksheet and built array with first row as header $objWorksheet = $objPHPExcel->getAllSheets(); //excel with first row header, use header as key $worksheet = array(); foreach ($objWorksheet as $key => $PHPExcel_Worksheet){ //excel sheet with no header $worksheet[$key] = $PHPExcel_Worksheet->toArray(null, true, true, false); } return $worksheet; } } Now You can use this Custom lib in your controller or model using CI's loader. For example your controller having method like below. function do_upload() { $config['upload_path'] = './uploads/'; $config['allowed_types'] = 'application/vnd.ms-excel|application/x-csv|text/x-csv|text/csv|application/csv|application/excel|application/vnd.msexcel|application/vnd.openxmlformats-officedocument.spreadsheetml.sheet|application/zip|application/vnd.ms-excel|application/excel|xls|xlsx|csv'; $config['max_size'] = '10240'; // in KB $this->load->library('upload', $config); $this->upload->do_upload(); $this->load->library('Excel'); $DatainArray = $this->excel->parseFile($this->upload->upload_path . $this->upload->file_name); //do some For loop and insert data to your database.enter code here var_dumpt($DatainArray); }
Validation and submit button don't function together in PartialView while using a composite model
Validation in my forms are defined in my Model. If I don't include these two lines in my view: $("#frmNewTemplate").removeData("validator").removeData("unobtrusiveValidation"); $.validator.unobtrusive.parse("#frmNewTemplate"); The submit button works fine, but validation doesn't work. If I include these, validation starts working and the submit button doesn't work anymore. I try to do the validation through my model. My model: public class TemplateDTO : DTOBase { public virtual int ID { get; set; } [Required(ErrorMessage="فيلد ضروري")] [RegularExpression("^[a-zA-z0-9\\-\\. ]+$", ErrorMessage = "کاراکترهاي وارد شده در محدوده کاراکترهاي مجاز نمي باشند")] public virtual string Name { get; set; } [RegularExpression("^[a-zA-zآ-ي0-9\\-\\. ]+$", ErrorMessage = "کاراکترهاي وارد شده در محدوده کاراکترهاي مجاز نمي باشند")] public virtual string Name_Fr { get; set; } public virtual IList<TemplateDetailsDTO> LstDetails { get; set; } } My composite model: public class TemplateViewModel { public TemplateDTO Template { get; set; } public List<TemplateFieldsDTO> TemplateFeilds { get; set; } public int[] oSelectedFieldsDTO { get; set; } public string Text { get; set; } public bool NextLine { get; set; } } My Controller (ActionResult which calls the view and JsonResult which is the answer): public ActionResult _NewTemplate() { if (myGlobalVariables.AllTemplateFieldsDTO == null) { TemplateFieldsClientService oTemplateFieldsClientService = new TemplateFieldsClientService(); myGlobalVariables.AllTemplateFieldsDTO = oTemplateFieldsClientService.GetAll(); } TemplateDTO oTemplateDTO = new TemplateDTO(); oTemplateDTO.LstDetails = new List<TemplateDetailsDTO>(); TemplateViewModel x = new TemplateViewModel(); x.TemplateFeilds = myGlobalVariables.AllTemplateFieldsDTO; x.Template = oTemplateDTO; return PartialView(x); } [HttpPost] public JsonResult _NewTemplate(TemplateViewModel oTemplateViewModel) { if (ModelState.IsValid) { if (oTemplateViewModel.Template != null) { if (oTemplateViewModel.Template.Name == null) { throw new System.ArgumentNullException("Parameter can not be null", "oTemplateDTO"); } string strAttr = ""; if (oTemplateViewModel.NextLine) strAttr = "\n"; List<TemplateDetailsDTO> LstTemDetails = new List<TemplateDetailsDTO>(); int Position = 0; if (oTemplateViewModel.oSelectedFieldsDTO != null) { foreach (var i in oTemplateViewModel.oSelectedFieldsDTO) { TemplateDetailsDTO TempDetls = new TemplateDetailsDTO(); TempDetls.PositionNumber = ++Position; TempDetls.Attributes = strAttr; TemplateFieldsDTO OTemplateFieldsDTO = myGlobalVariables.AllTemplateFieldsDTO.Find(x => x.ID == i); TempDetls.ObjFields = OTemplateFieldsDTO; TempDetls.ObjTemplate = oTemplateViewModel.Template; LstTemDetails.Add(TempDetls); } } oTemplateViewModel.Template.LstDetails = LstTemDetails; oTemplateClientService.AddNewTemplate(oTemplateViewModel.Template); myGlobalVariables.AllTemplateDTO = oTemplateClientService.GetAllTemplate(); log.Info("Template added to Database."); return Json(new { Result = "OK", Message = "عمليات ثبت با موفقيت انجام شد" }, JsonRequestBehavior.DenyGet); } else { return Json(new { Result = "Error", Message = "لطفا فيلدها را وارد نماييد" }, JsonRequestBehavior.DenyGet); } } else { return Json(new { Result = "Error", Message = "لطفا فيلدها ي ضروري را وارد نماييد" }, JsonRequestBehavior.DenyGet); } } Code for my view: #model IAC.SMS.MvcApp.Controllers.TemplateViewModel <script type="text/javascript"> $(function () { $("#frmNewTemplate").removeData("validator").removeData("unobtrusiveValidation"); $.validator.unobtrusive.parse("#frmNewTemplate"); $('#btnAdd').click(function () { $('#ListBoxSource').find('option:selected').appendTo('#oSelectedFieldsDTO'); }) $('#btnDelete').click(function () { $('#oSelectedFieldsDTO').find('option:selected').appendTo('#ListBoxSource'); }); $('#btnUp').click(function () { var selectedOption = $('#oSelectedFieldsDTO').find('option:selected'); var prevOption = $('#oSelectedFieldsDTO').find('option:selected').prev("option"); if ($(prevOption).text() != "") { $(selectedOption).remove(); $(prevOption).before($(selectedOption)); } }); $('#btnDown').click(function () { var selectedOption = $('#oSelectedFieldsDTO').find('option:selected'); var nextOption = $('#oSelectedFieldsDTO').find('option:selected').next("option"); if ($(nextOption).text() != "") { $(selectedOption).remove(); $(nextOption).after($(selectedOption)); } }); }); function display() { var dpt = document.getElementById("oSelectedFieldsDTO"); if (dpt.options[dpt.selectedIndex].text == "Text") { document.getElementById("Text").disabled = false; } }; function SelectAllItems() { $("#oSelectedFieldsDTO").each(function () { $("#oSelectedFieldsDTO option").attr("selected", "selected"); }); }; //functions for ajax begin form function Refresh() { window.location.href = "#Url.Action("ListTemplate", "Template")" + "/"; } function Success(data) { if (data.Result == "OK") { jSuccess( data.Message, { autoHide: true, // added in v2.0 clickOverlay: false, // added in v2.0 MinWidth: 200, TimeShown: 1500, ShowTimeEffect: 1000, HideTimeEffect: 500, LongTrip: 20, HorizontalPosition: 'center', VerticalPosition: 'center', ShowOverlay: true, ColorOverlay: '#000', OpacityOverlay: 0.3, }); Refresh(); } else { jSuccess( data.Message, { autoHide: true, // added in v2.0 clickOverlay: false, // added in v2.0 MinWidth: 200, TimeShown: 1500, ShowTimeEffect: 1000, HideTimeEffect: 500, LongTrip: 20, HorizontalPosition: 'center', VerticalPosition: 'center', ShowOverlay: true, ColorOverlay: '#000', OpacityOverlay: 0.3, }); } } function Fail() { jSuccess( 'ارتباط برقرار نشد', { autoHide: true, // added in v2.0 clickOverlay: false, // added in v2.0 MinWidth: 200, TimeShown: 1500, ShowTimeEffect: 1000, HideTimeEffect: 500, LongTrip: 20, HorizontalPosition: 'center', VerticalPosition: 'center', ShowOverlay: true, ColorOverlay: '#000', OpacityOverlay: 0.3, }); } </script> #using (Ajax.BeginForm("_NewTemplate", "Template", new AjaxOptions { InsertionMode = InsertionMode.Replace, HttpMethod = "POST", OnSuccess = "Success", OnFailure = "Fail", LoadingElementId = "Loading" }, new { #id = "frmNewTemplate" })) { <table id="tblDetails" class="dataInput" style="width:500px;"> <tr> <td></td> <td></td> <td></td> <td> <label> ليست مبدا </label> </td> </tr> <tr> <td> <label> نام قالب </label> </td> <td> #Html.TextBoxFor(model => model.Template.Name) <label style="color:red; font-weight:bold;">*</label> #Html.ValidationMessageFor(model => model.Template.Name) </td> <td></td> <td rowspan="3"> #Html.ListBox("ListBoxSource", new SelectList(Model.TemplateFeilds, "ID", "Name", 1), new { size = 10 , style = "width:200px"}) </td> </tr> <tr> <td> <label> توضيحات </label> </td> <td> #Html.TextBoxFor(model => model.Template.Name_Fr) </td> </tr> <tr> <td> <label> پيام تکميلي </label> </td> <td> #Html.TextBoxFor(model => model.Text , new { disabled="disabled"}) </td> <td> </td> </tr> <tr> <td> #Html.CH_CheckBoxFor(model=>model.NextLine, "خط بعد", false, false) </td> <td></td> <td></td> <td> <button class="fixed button" id="btnAdd" type="button">اضافه<span class="left"></span> </button> <button class="fixed button" id="btnDelete" type="button">حذف<span class="right"></span> </button> </td> </tr> <tr> <td></td> <td></td> <td></td> <td> <label> ليست مقصد </label> </td> </tr> <tr> <td> </td> <td></td> <td></td> <td> #Html.ListBoxFor(model => model.oSelectedFieldsDTO, new SelectList(Model.Template.LstDetails, "ID", "Name", 1), new { size = 10, style = "width:200px", onchange = "display()" }) </td> </tr> <tr> <td></td> <td></td> <td> </td> <td> <button class="fixed button" id="btnUp" type="button">بالا<span class="up"></span> </button> <button class="fixed button" id="btnDown" type="button">پايين<span class="down"></span> </button> </td> </tr> <tr> <td> #Html.HiddenFor(model=>model.Template.ID) </td> </tr> </table> <table> <tr> <td></td> <td> <div> <button class="fixed button" type="submit" onmouseover="SelectAllItems()">ذخيره</button> </div> </td> </tr> </table> } Please tell me if I should include any more code. My problem is that when I include the two lines code I mentioned above in my View to have validation, submit button in my PartialView won't function anymore, and the control doesn't go to the JsonResult function of my controller. Thanks in Advance.
Update jquery.validate.min.js to version v1.12.0 - 4/1/2014 . I hope you get the problem solved .