Im using mPDF to generate PDFs and send reports to the clients.
I'm using this foreach to fill my table row
$report_nr = $this->input->post('report_nr');
$date = $this->input->post('date');
$owner = $this->input->post('owner');
$ar1 = $this->input->post('column01');
$ar2 = $this->input->post('column02');
$ar3 = $this->input->post('column03');
$ar4 = $this->input->post('column04');
$ar5 = $this->input->post('column05');
$ar6 = $this->input->post('column06');
$ar7 = $this->input->post('column07');
$ar8 = $this->input->post('column08');
$ar9 = $this->input->post('column09');
$ar10 = $this->input->post('column10');
include('../mpdf.php');
$mpdf = new mPDF('', // mode - default ''
'A4', // format - A4, for example, default ''
0, // font size - default 0
'', // default font family
15, // margin_left
15, // margin right
16, // margin top
16, // margin bottom
9, // margin header
9, // margin footer
'P'); // L - landscape, P - portrait
//$this->customer_report();
$n=0; //start counting at 0, like array counters do.
foreach ($ar2 as $thing) { //for each value of $ar2
$bigar[$n][2] = $thing; //set $bigarray at $n at 1 to that part
$n++; //add one to $n, continue
}
$n=0; //repeat for array 3
foreach ($ar3 as $thing) {
$bigar[$n][3] = $thing; //now use the 2 value of the array
$n++;
}
$n=0; //repeat for array 4
foreach ($ar5 as $thing) {
$bigar[$n][5] = $thing; //now use the 2 value of the array
$n++;
}
$n=0; //start counting at 0, like array counters do.
foreach ($ar6 as $thing) { //for each value of $ar2
$bigar[$n][6] = $thing; //set $bigarray at $n at 1 to that part
$n++; //add one to $n, continue
}
$n=0; //repeat for array 3
foreach ($ar8 as $thing) {
$bigar[$n][8] = $thing; //now use the 2 value of the array
$n++;
}
$n=0; //repeat for array 4
foreach ($ar9 as $thing) {
$bigar[$n][9] = $thing; //now use the 2 value of the array
$n++;
}
$n=0; //repeat for array 1
foreach ($ar1 as $thing) {
$bigar[$n][1] = $thing; //now use the 2 value of the array
$n++;
}
$this->mpdf->WriteHTML("<table border='1'>");
$this->mpdf->WriteHTML('<thead><tr><th class="span1">Relatório Nº :</th><th> '.$report_nr.' </th><th>Data :</th><th> '.$date.' </th><th>Cliente :</th><th colspan="5"> '.$owner.' </th></tr></thead>');
$this->mpdf->WriteHTML("<tbody>");
$this->mpdf->WriteHTML("<tr>");
foreach ($bigar as $part) { //go through each chunk of the array
if($i%10 == 0 && $i != 0) {
$this->mpdf->WriteHTML("</tr>");
$this->mpdf->WriteHTML("<tr>");
}
$this->mpdf->WriteHTML("<td>");
$this->mpdf->WriteHTML("<table><tbody><tr><td> ".($part[2]+$part[3])." </td><td> ".($part[5]+$part[6])." </td><td> ".($part[8]+$part[9]).' </td></tr><tr><td colspan="3"> '.$part[1]." </td></tr></tbody></table>");
$this->mpdf->WriteHTML("</td>"); //now, like above, that part has [1], and [2]
$i++;
}
$this->mpdf->WriteHTML("</tr>");
$this->mpdf->WriteHTML("</tbody></table>");
As u can see on the last row...when i reach 10 cells, it create another row.
Now i need the last row to get to 10 cells even if no content on the arrays, otherwise it won't create the complete row, which makes my table a mess in the end...
Here's a printscreen of the pdf:
Hope i made myself clear.
Thank you all
Found a way of doing it and i want to share with u.
}
$this->mpdf->WriteHTML('<table border="1">');
$this->mpdf->WriteHTML('<thead><tr><th>Relatório Nº :</th><th> '.$report_nr.' </th><th>Data :</th><th> '.$date.' </th><th>Cliente :</th><th colspan="5"> '.$owner.' </th></tr></thead>');
$this->mpdf->WriteHTML("<tbody>");
$this->mpdf->WriteHTML("<tr>");
foreach ($bigar as $part) { //go through each chunk of the array
if($i%10 == 0 && $i != 0) {
$this->mpdf->WriteHTML('</tr>');
$this->mpdf->WriteHTML('<tr>');
}
$this->mpdf->WriteHTML("<td>");
$this->mpdf->WriteHTML("<table border='1'><tbody><tr><td> ".($part[2]+$part[3])." </td><td> ".($part[5]+$part[6])." </td><td> ".($part[8]+$part[9]).' </td></tr><tr><td colspan="3"> '.$part[1]." </td></tr></tbody></table>");
$this->mpdf->WriteHTML("</td>"); //now, like above, that part has [1], and [2]
$i++;
}
$this->mpdf->WriteHTML('<td colspan="'.(10-($i%10)).'"></td></tr>');
$this->mpdf->WriteHTML("</tbody></table>");
//$bigar_removed = ereg_replace("0", "", $bigar);
//$this->mpdf->WriteHTML("".$bigar_removed."");
$this->mpdf->WriteHTML("<pagebreak>");
$this->mpdf->Output();
exit;
}
The trick was find a way of know which cell number was last created in the row.
$this->mpdf->WriteHTML('<td colspan="'.(10-($i%10)).'"></td></tr>');
This way, i just substracted the number from 10, which left me with the number to use with coldspan, having the row complete.
Hope it helps some of u!!
Thank you all
Related
Is it possible to fasten the hide of many rows when range.length > 300 rows ?
I also can't succeed moving the focus to the top of the sheet once the rows are hidden, I can only get the focus on another sheet.
Here is my code (french parameters), I'm not sure I need to show my spreadsheet. Thank you very much.
var LastRow = sheet.getLastRow()-1;
var ToHide = [];
for (var i=1 ; i < LastRow +1 ; i++){
if ( sheet.getRange(i,1).isChecked() == null){ ToHide.push(i); }
}
for (var j=0 ; j<ToHide.length ; j++){ MyActiveSheet.hideRows(ToHide[j+1],1); }
ToHide.forEach(function (d){ FeuilleActive.hideRows(d); }); // also tried .hideRows(d,1)
SpreadsheetApp.getActive().getSheets()[5].getRange(1,1).activate(); //
To lessen the number of loops, you can group it by determining the series of consecutive numbers in your Array. Which you can use to determine the index and number of rows to hide. The number of .hideRows() execution will be determined by the number of series in your array. Thus, lesser runtime.
Example Code:
function myFunction() {
var a = [1,2,3,4,6,7,8,9,11,13,14];
const result = a.reduce((r, n) => {
const lastSubArray = r[r.length - 1];
if(!lastSubArray || lastSubArray[lastSubArray.length - 1] !== n - 1) {
r.push([]);
}
r[r.length - 1].push(n);
return r;
}, []);
//result output: [[1.0, 2.0, 3.0, 4.0], [6.0, 7.0, 8.0, 9.0], [11.0], [13.0, 14.0]]
result.forEach(e => {
var index = e[0];
var numRows = e.length;
Logger.log("Index: "+ index);
Logger.log("numRows: "+numRows);
// MyActiveSheet.hideRows(index,numRows);
})
}
Output:
References:
Ori Drori answer on how to group series of consecutive numbers in an Array.
hideRows(rowIndex, numRows)
I'm trying to create a PDF based off of an interactive/dynamic table using jsPDF + AutoTable. The last cell in a row will either say "Yes" or "No" - if the cell says "Yes" the entire row should be highlighted.
The closest I've come is getting the cell to highlight, but I need the entire row to highlight. I seem to be having trouble tying the cell to the row index.
This is my code so far:
willDrawCell: function (data) {
if (data.cell.text == "Yes") {
doc.setFillColor(67, 160, 71);
}
}
Thanks for any help.
I was able to resolve this!
Before my doc.autoTable() call, I calculate the index where the "Yes" is, and store those values in an array. I then loop over each row index and setFillColor as appropriate. Here is what my code looks like now:
willDrawCell: function (data) {
if (data.cell.text == "Yes") {
doc.setFillColor(67, 160, 71);
}
for (let i = 0; i < ready_rows.length; i++) {
if (data.row.index === ready_rows[i]) {
doc.setFillColor(239, 154, 154);
}
}
}
here currentRow is row which given in auto table
var res1 = doc.autoTableHtmlToJson(document.getElementById(m));
var idmm=document.getElementById(n);
var clength=res1.columns.length;
var crow=res1.rows.length;
doc.autoTable(res1.columns, res1.data, {margin: {top: vy+25},pageBreak: 'auto',styles: {cellPadding: 1.5,fontSize:fsize , },fontStyle: 'bold',drawRow: function (row, data) {
currentRow1 = row;
currentRow1.height =30;
if((currentRow1.cells[0].text[0].includes('Total')) || (currentRow1.cells[0].text[0].includes('Avg'))||(currentRow1.cells[0].text[0].includes('count'))||(currentRow1.cells[0].text[0].includes('Min'))||(currentRow1.cells[0].text[0].includes('Max')))
{
1
for(var i=0;i<res1.columns.length;i++)
{
currentRow1.cells[i].styles.fontStyle = "bold";
currentRow1.cells[i].styles.font = "sans-serif" ;
currentRow1.cells[i].styles.fillColor = [243,205,204];
currentRow1.cells[1].styles.columnWidth="wrap";
currentRow1.cells[1].styles.FontSize=30;
}
}
},columnStyles: {0: {columnWidth: columnwidthrgroup},},});
```
So I've created sort of radio button chooser table with check boxes so I can pick which line I want and that brings the value from this line out to the result cell...
this is the basic principle:
this way which ever checkbox I click, the value of that cell becomes 1 (TRUE) rather than 0 (FALSE), and using SUMPRODUCT formula, every line is multiplied by the boolean checkbox so if the checkbox is not checked, the production is zeroed, and if the checkbox is checked, the value remains.
In this example on B8 I get:
B8 = A2*B2 + A3*B3 + A4*B4 = 0*3 + 1*8 + 0*12 = 8
That works well as long as the values are numbers..
Now I'm trying to do the same but with string values..
something like this:
Any idea?
Solution:
Use IF to get corresponding Col B
JOIN the resulting array
Sample:
=ARRAYFORMULA(TEXTJOIN(",",1,IF(A2:A4,B2:B4,)))
I used the checkbox and Google Apps Script, where column A (1) and column B (2) contain the checkboxes. For example:
function onEdit(evt) {
var range = evt.range;
var val = range.getValue();
var row = range.getRow();
var col = range.getColumn();
// -------------------------------------
// --- Cannot be both add and delete ---
// -------------------------------------
if (col == 1) {
if (val) {
SpreadsheetApp.getActiveSheet().getRange(row,2).setValue('FALSE');
}
}
else if (col == 2) {
if (val) {
SpreadsheetApp.getActiveSheet().getRange(row,1).setValue('FALSE');
}
}
}
I would like to share my codes. Please run onStart() for setting up radio boxes as well.
function onEdit(e) {
// radio button
var ss = SpreadsheetApp.getActiveSpreadsheet();
var gsheetrange = gsheet.getDataRange().getValues();
var rowcount = gsheetrange.length; // find end of row
for(var i = 0; i <= rowcount; i++) { // start from 0.
if (i==gedited){
gsheet.getRange(gedited, 2).setValue("true");
}
else
{
gsheet.getRange(i, 2).setValue("false");
}
}
}
I'm looking to clone a row 3x, but only keeping data from one column.
So essentially I have the following [Name / Time / Booking], and each row is populated with all 3 properties, I'm trying to create 3 blank rows underneath each current row which is populated with only the persons name.
Can't work how to do it in scripting and can't find a plugin to do this. My data set is over 10,000 big so doing it manually isn't an option.
What I have:
What I want:
UPDATED code:
function duplicateRows() {
var sh, v, arr, c, b;
sh = SpreadsheetApp.getActive()
.getSheetByName('Blad1')
v = sh.getRange(1, 1, sh.getLastRow(), 40)
.getValues();
arr = [v[0]];
v.splice(1)
.forEach(function (r, i) {
arr.push(r)
c = 0
while (c < 3) {
dup = makeEmptyArrayXEl(40)
dup[0] = r[0];
arr.push(dup)
c += 1;
}
})
sh.getRange(1, 1, arr.length, arr[0].length)
.setValues(arr);
}
function makeEmptyArrayXEl(num) {
var arr = [];
for (var i = 0; i < num; i++) {
arr.push("")
}
return arr;
}
Would this work for you? It requires a free column to the left of Booking in the original data set. The formula below is a new sheet.
=ArrayFormula(sort({A2:A4,B2:B4,C2:C4;A2:A4,D2:D4,D2:D4;A2:A4,D2:D4,D2:D4;A2:A4,D2:D4,D2:D4},1,FALSE))
I have 30 columns and 1000 rows, I would like to compare column1 with another column. IF the value dont match then I would like to colour it red. Below is a small dataset in my spreadsheet:
A B C D E F ...
1 name sName email
2
3
.
n
Because I have a large dataset and I want to storing my columns in a array, the first row is heading. This is what I have done, however when testing I get empty result, can someone correct me what I am doing wrong?
var index = [];
var sheet = SpreadsheetApp.getActiveSheet();
function col(){
var data = sheet.getDataRange().getValues();
for (var i = 1; i <= data.length; i++) {
te = index[i] = data[1];
Logger.log(columnIndex[i])
if (data[3] != data[7]){
// column_id.setFontColor('red'); <--- I can set the background like this
}
}
}
From the code you can see I am scanning whole spreadsheet data[1] get the heading and in if loop (data[3] != data[7]) compare two columns. I do have to work on my colour variable but that can be done once I get the data that I need.
Try to check this tutorial if it can help you with your problem. This tutorial use a Google AppsScript to compare the two columns. If differences are found, the script should point these out. If no differences are found at all, the script should put out the text "[id]". Just customize this code for your own function.
Here is the code used to achieve this kind of comparison
function stringComparison(s1, s2) {
// lets test both variables are the same object type if not throw an error
if (Object.prototype.toString.call(s1) !== Object.prototype.toString.call(s2)){
throw("Both values need to be an array of cells or individual cells")
}
// if we are looking at two arrays of cells make sure the sizes match and only one column wide
if( Object.prototype.toString.call(s1) === '[object Array]' ) {
if (s1.length != s2.length || s1[0].length > 1 || s2[0].length > 1){
throw("Arrays of cells need to be same size and 1 column wide");
}
// since we are working with an array intialise the return
var out = [];
for (r in s1){ // loop over the rows and find differences using diff sub function
out.push([diff(s1[r][0], s2[r][0])]);
}
return out; // return response
} else { // we are working with two cells so return diff
return diff(s1, s2)
}
}
function diff (s1, s2){
var out = "[ ";
var notid = false;
// loop to match each character
for (var n = 0; n < s1.length; n++){
if (s1.charAt(n) == s2.charAt(n)){
out += "–";
} else {
out += s2.charAt(n);
notid = true;
}
out += " ";
}
out += " ]"
return (notid) ? out : "[ id. ]"; // if notid(entical) return output or [id.]
}
For more information, just check the tutorial link above and this SO question on how to compare two Spreadsheets.