jsPDF Table Width & Font Size - jspdf

I thought this would be relatively simple but I cannot find an answer anywhere, I have had a good hunt in Stack Overflow. Apologies if I have missed something obvious!
How on earth do you set the table width in jsPDF? I simply want my table to stretch to 100% of the page width. Here is the code I am using:
<script>
function demoFromHTML() {
var pdf = new jsPDF('p', 'pt', 'a4');
source = $('#pdf')[0];
specialElementHandlers = {
'#bypassme': function (element, renderer) {
return true
}
};
margins = {
top: 80,
bottom: 40,
left: 40,
width: 600
};
pdf.fromHTML(
source,
margins.left,
margins.top, {
'width': margins.width,
'elementHandlers': specialElementHandlers
},
function (dispose) {
pdf.output('datauri');
}, margins);
}
</script>
I am using standard, unformatted HTML table.
<table class="reference">
<tbody><tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Points</th>
</tr>
<tr>
<td>Jill</td>
<td>Smith</td>
<td>50</td>
</tr>
<tr>
<td>Eve</td>
<td>Jackson</td>
<td>94</td>
</tr>
<tr>
<td>John</td>
<td>Doe</td>
<td>80</td>
</tr>
<tr>
<td>Adam</td>
<td>Johnson</td>
<td>67</td>
</tr>
</tbody></table>
The table only stretches about 60% across the PDF, which just seems to be a random amount. In addition the text inside the table is a different font and size to the text outside the table.
Any help would be greatly appreciated.

Related

Tablesorter custom equations on calculated data

I need to sum two columns, then find the difference between those two. The use case is simple: in one column I have all the purchases and the second one contains all the transactions, the user will see the difference.
Here is the relevant code for the calculation:
<tfoot>
<tr>
<th>Total</th>
<th data-math="col-sum"></th>
<th data-math="col-sum"></th>
<th data-math="row-difference"></th>
</tr>
</tfoot>
And the formula can be something really simple like
$.tablesorter.equations['difference'] = function(arry) {
return arry[1] - arry[2];
};
How would you make it work?
The way the math widget is set up, it prioritizes rows calculations before column calculations. So in this case, the footer row will try to calculate the row difference before calculating the column sum.
To fix this, change the math_priority widget option so that the 'col' comes before 'row' (demo):
$(function() {
$.tablesorter.equations.difference = function(arry) {
return arry[1] - arry[2];
};
$("table").tablesorter({
theme: 'blue',
widgets: ['math', 'zebra'],
widgetOptions: {
// default [ 'row', 'above', 'below', 'col' ]
// move 'col' first in this case
math_priority: ['col', 'row', 'above', 'below']
}
});
});

syncing jquery ui select menu with knockout observable array

probably going about this the wrong way but I have an html table that is populated using a knockout observable array using foreach. in each row I have a drop down. I like the jquery ui select menu so I am using that. unfortunately when you run the fiddle you will notice that when updating the drop down the corresponding knockout selected value is not being updated.
here is the fiddle https://jsfiddle.net/8rw4ruze/3/
here is the html.
<table class="table table-condensed table-responsive">
<thead>
<th>id</th>
<th>animal</th>
<th>Selected Value</th>
</thead>
<tbody data-bind="foreach: tableRows">
<tr>
<td data-bind="text: id"></td>
<td>
<select class="form-control" data-bind="options: recordList,
optionsText: 'desc',
optionsValue: 'val',
value: selectedVal,
attr: {id: selectId}">
</select>
</td>
<td data-bind="text: selectedVal"></td>
</tr>
</tbody>
</table>
and here is the javascript
function record(val, desc) {
var self = this;
this.val = ko.observable(val);
this.desc = ko.observable(desc);
}
function tableRow(id, recordList) {
var self = this;
this.id = ko.observable(id);
this.recordList = ko.observable(recordList)
this.selectedVal = ko.observable('A');
this.selectId = ko.computed(function() {
return 'mySelect' + self.id()
}, this);
}
function Model() {
var self = this;
this.records = ko.observableArray("");
this.tableRows = ko.observableArray("");
}
var mymodel = new Model();
$(function() {
mymodel.records.push(new record('A', 'ant'));
mymodel.records.push(new record('B', 'bird'));
mymodel.records.push(new record('C', 'cat'));
mymodel.records.push(new record('D', 'dog'));
mymodel.tableRows.push(new tableRow(1, mymodel.records()));
mymodel.tableRows.push(new tableRow(2, mymodel.records()));
mymodel.tableRows.push(new tableRow(3, mymodel.records()));
mymodel.tableRows.push(new tableRow(4, mymodel.records()));
ko.applyBindings(mymodel);
for (var i = 0; i < 4; i++) {
var id = '#mySelect' + (i + 1)
$(id).selectmenu({
width: 125,
change: function(event, ui) {
var newVal = $(this).val();
mymodel.tableRows()[i].selectedVal(newVal);
}
});
}
});
thanks all I went with a data attribute. I'd prefer to use the custom binding but I'm not smart enough to figure that out so I went with this.
for (var i = 0; i < 4; i++) {
var id = '#mySelect' + (i + 1)
$(id).selectmenu({
width: 125,
change: function(event, ui) {
var newVal = $(this).val();
var index = $(this).data( "index" );
mymodel.tableRows()[index].selectedVal(newVal);
}
}).data( "index", i );
}
here is the fiddle https://jsfiddle.net/8rw4ruze/7/
I think I got it working with the custom binding here it is
https://jsfiddle.net/8rw4ruze/8/
Matt.k is correct that your value of i is not what you want it to be when it is used. One way around that is to use this loop instead of a simple for:
$('select').each(function (i, e) {
e.selectmenu({
width: 125,
change: function(event, ui) {
var newVal = $(this).val();
mymodel.tableRows()[i].selectedVal(newVal);
}
});
});
This is a little fragile, as it relies on the i and the e to correspond correctly. A more robust (and typical in Knockout) approach is to use a binding handler, which would allow you to specify the binding and have Knockout go through the elements and make the necessary calls. Surprisingly, a little web-searching didn't turn one up for me.
I see there is a knockout-jqueryui project on github that might also give you a clean way of using the widgets you want.

jQueryUI resizable - when you change the width of a column - all the other speakers twitch

I use jQueryUI resizable for resizing columns in the table.
When you change the width of one column, the other columns must remain unchanged. Should only varies the width of the table
Why do you change the width of one column, while others twitch? If all columns to make the minimum width, and then begin to increase the width of the last column (right column), all the others begin to twitch.
<div class="table-wrapper">
<table id="table">
<tbody>
<tr>
<td class="gray">Zagreb</td>
<td class="gray">Kinshasa</td>
<td class="gray">Kishinev</td>
<td class="gray">Krakow</td>
<td class="gray">Lima</td>
<td class="gray">Lisbon</td>
</tr>
<tr>
<td>Zagreb</td>
<td>Kinshasa</td>
<td>Kishinev</td>
<td>Krakow</td>
<td>Lima</td>
<td>Lisbon</td>
</tr>
<tr>
<td>Zagreb</td>
<td>Kinshasa</td>
<td>Kishinev</td>
<td>Krakow</td>
<td>Lima</td>
<td>Lisbon</td>
</tr>
<tr>
<td>Zagreb</td>
<td>Kinshasa</td>
<td>Kishinev</td>
<td>Krakow</td>
<td>Lima</td>
<td>Lisbon</td>
</tr>
<tr>
<td>London</td>
<td>Los Angeles</td>
<td>Luxembourg</td>
<td>Madrid</td>
<td>Manila</td>
<td>Mexico</td>
</tr>
<tr>
<td>Milan</td>
<td>Montreal</td>
<td>Mumbai</td>
<td>Nairobi</td>
<td>Nicosia</td>
<td>New York</td>
</tr>
<tr>
<td>Osaka</td>
<td>Oslo</td>
<td>Ottawa</td>
<td>Paris</td>
<td>Prague</td>
<td>Riga</td>
</tr>
<tr>
<td>Rome</td>
<td>Rotterdam</td>
<td>Salvador</td>
<td>Samarkand</td>
<td>Sydney</td>
<td>Singapore</td>
</tr>
<tr>
<td>Sofia</td>
<td>Istanbul</td>
<td>Taipei</td>
<td>Tbilisi</td>
<td>Zurich</td>
<td>Chicago</td>
</tr>
</tbody>
</table>
</div>
JS code:
$(document).ready(function(e)
{
var $table = $("#table");
var startW = 0;
var startW_neighbor = 0;
var td_index_neighbor = 0;
var ui_minColWidth = 0;
$table.find("tr:first th, tr:first td").resizable(
{
handles: 'e',
minWidth: 30,
start : function(event,ui)
{
ui_minColWidth = $(this).resizable( "option", "minWidth");
startW = $(this).width();
startW_neighbor = ui.element.parents('.table-wrapper').find('table#table').width();
},
stop: function (event, ui)
{
},
resize: function (event, ui)
{
var td_width = ui.element.width();
var table = ui.element.parents('.table-wrapper').find('table#table');
var d = Number(td_width) - Number(ui.originalSize.width);
td_width = Number(startW_neighbor) + Number(d) - 2;
table.width(td_width);
}
});
});
In example: http://jsfiddle.net/djmartini/08p3Lqcm/
You're at the same time interfering with normal behavior of resizable and relying on it to calculate some values, so at some point it breaks. In that case you're calculating the width difference based on resizable behavior and applying it to change the behavior. But when resizable doesn't have any more place to resize, the difference is 0, hence nothing moves anymore.
If you want to change the behavior of resizable, you could work with mouse position and micro manage the change in width. In that case you'll need to handle cases where your mouse moves, but nothing gets resized. This happens when columns cannot reduce size anymore.
Something like this seems to work:
$table.find("tr:first th, tr:first td").resizable({
handles: 'e',
minWidth: 30,
start: function (event, ui) {
ui_minColWidth = $(this).resizable("option", "minWidth");
startW = $(this).width();
td_width = startW;//this to check if width can change
startW_neighbor = ui.element.parents('.table-wrapper').find('table#table').width();
startMouseX = event.pageX;//to calculate mouse diffrence
},
stop: function (event, ui) {
},
resize: function (event, ui) {;
var mouseDiff = event.pageX - startMouseX;//mouse mouvement
//If the mouse is negative, it can resize only if column
//isn't at min width. When mouse positive resize always.
if (ui.element.width() != td_width || mouseDiff > 0) {
td_width = ui.element.width();
var table = ui.element.parents('.table-wrapper').find('table#table');
var d = Number(td_width) - Number(ui.originalSize.width);
table_width = Number(startW_neighbor) + mouseDiff;
table.width(table_width);
}
}
});
fiddle: http://jsfiddle.net/wLbn5qjk/1/
EDIT:
You can push this logic and work with alsoResize, the result is a bit better:
$table.find("tr:first th, tr:first td").resizable({
handles: 'e',
minWidth: 30,
alsoResize: 'table',
start: function (event, ui) {
ui_minColWidth = $(this).resizable("option", "minWidth");
startW = $(this).width();
td_width = ui.element.width();
startW_neighbor = ui.element.parents('.table-wrapper').find('table#table').width();
startMouseX = event.pageX;
},
stop: function (event, ui) {
},
resize: function (event, ui) {;
var mouseDiff = event.pageX - startMouseX;
if (ui.element.width() == td_width && mouseDiff < 0) {;
$('table').width(table_width);
}
td_width = ui.element.width();
table_width = $('table').width()
}
});
http://jsfiddle.net/hrzj68wp/1/

How to save Jspdf file into specific folder

i am using jspdf to generate a pdf.Its working but the file is download to "Download" folder.but i want to download specific folder like this("localhost/ccs/ccs/invoice") folder path to save the generated pdf.how to solve to change in my code. my example code is
<div class="invoice" id="customers" ng-repeat="aim in input">
<div align="right"><h1 align="right"><b>INVOICE</b> </h1></div>
<table>
<tr>
<td>
Hello
</td>
<td>
Hi
</td>
</tr>
</table>
</div>
<button onclick="javascript:demoFromHTML();">PDF</button>
my scripting code is
<script>
function demoFromHTML() {
var pdf = new jsPDF('p', 'pt', 'letter');
// source can be HTML-formatted string, or a reference
// to an actual DOM element from which the text will be scraped.
source = $('#customers')[0];
// we support special element handlers. Register them with jQuery-style
// ID selector for either ID or node name. ("#iAmID", "div", "span" etc.)
// There is no support for any other type of selectors
// (class, of compound) at this time.
specialElementHandlers = {
// element with id of "bypass" - jQuery style selector
'#bypassme': function (element, renderer) {
// true = "handled elsewhere, bypass text extraction"
return true
}
};
margins = {
top: 80,
bottom: 60,
left: 40,
width: 522
};
// all coords and widths are in jsPDF instance's declared units
// 'inches' in this case
pdf.fromHTML(
source, // HTML string or DOM elem ref.
margins.left, // x coord
margins.top, {// y coord
'width': margins.width, // max width of content on PDF
'elementHandlers': specialElementHandlers
},
function (dispose) {
// dispose: object with X, Y of the last line add to the PDF
// this allow the insertion of new lines after html
pdf.save('Invoice.pdf');
}, margins);
}
</script>
<script type="text/javascript" src="http://mrrio.github.io/jsPDF/dist/jspdf.debug.js"> </script>
Thank you.
You could use 'FileSaver.js' along with jspdf.js, it will help you to save pdf in specific folder whereever you like.
var pdf = new jsPDF();
// your code here to write something in to pdf.
pdf.save(fileName);

one idea for jqgrid print view

I would like to have two views in jqgrid:
1) the regular grid view with sortable columns, pagination, etc (It's great and works really well...love it!).
2) a "print view" which can easily be styled with css and customized for print. The class structure should not be too complicated because I want to easily make my own style sheet. One important thing is to be able to repeat the column headers on each printed page. (I do not like to print from a jqgrid. Even when I add the jqgrid stylesheet with "media=print", the printed results are very hard to control.)
So, what I did was to first create a jqGrid. Then, using it's data, create my own table and print from that. It's a bit of a hack. But it works.
1- Create the grid and insert it into a div. Note I called "build_print_view" in the "loadComplete" function, based on the presence of a variable. This allows me to control whether I want to show "print view" or a "grid view" first:
function classGrid(select_val, showgrid){
jQuery.get('/lookupgrid/lookupgrid/get_grid', function(data) {
var _html= jQuery(data);
jQuery('#resultdiv').html(_html);
var gridtable = jQuery("#list");
var formdata = new Array();
formdata.push({
name: "var1",
value: "whatever"
});
formdata.push({
name: "var2",
value: "whateverelse"
});
var lastsel;
console_log("in classGrid");
gridtable.jqGrid({
url:'/lookupgrid/lookupgrid/class_grid',
colNames:['var1','var2'],
colModel :[
{
name:'var1',
index:'var1',
width:95
},
{
name:'var2',
index:'var2',
width:95
}],
datatype: 'json',
mtype: 'POST',
pager: '#pager',
rowList:[10,20,30],
loadComplete: function() {
if(!showgrid){
build_print_view();
}
},
onSelectRow: function(id){
var rowdata = gridtable.jqGrid('getRowData',id);
alert('Selected row ID ' + id + " var1 is " + rowdata.var1);
},
loadonce: true,
postData:formdata,
width: 800,
height: 300,
pgtext:"Page {0}",
viewrecords: true,
gridview: true,
caption: 'Class Results'
});
gridtable.jqGrid('navGrid','#pager',{
edit:false,
add:false,
del:false
});
});
}
2 - In build_print_view() you can extract the data from the jqgrid and put it into a table, which can be styled however you like with your own stylesheets.
function build_print_view(){
var gridtable = jQuery("#list");
var lista = gridtable.jqGrid('getGridParam','data');
var tablestr = "";
for(var i=0;i<lista.length;i++){
var rowData = lista[i];
tablestr += "<tr>"
tablestr += "<td class=\"wide cycle\" style=\"width:50px;\" id=\"sku\">"+rowData.var1+"</td>";
tablestr += "<td class=\"wide cycle\" style=\"width:300px;\" id=\"skudesc\">"+rowData.var2+"</td>";
tablestr += "</tr>";
}
jQuery.get('/lookupgrid/lookupgrid/get_print_view', function(data) {
var _html= jQuery(data);
_html.find('#printresults').append(tablestr);
jQuery('#resultdiv').html(_html);
});
}
3 - The rest of the table, and etc tags are returned by the ajax "get" call to "/lookupgrid/lookupgrid/get_print_view" and I just plop tablestr into "#printresults" div, i.e.:
<div id="printview">
<table id="clsitems" class="wide">
<thead>
<tr>
<th colspan="10" class="wide" id="label">
</th>
</tr>
<tr>
<td class="wide label">
var1:
</td>
<td class="wide label">
var2:
</td>
</tr>
</thead>
<tbody id="printresults">
</tbody>
</table>
</div>
4 - The only weirdness is that if "print view" is requested, the jqGrid gets created and flashes on the screen for a second, and then the print view table replaces it in its div.
Actually, if there were a good way to just construct the jqGrid without displaying it, I would prefer that. I could then display the jqGrid later if "screen view" were requested.

Resources