I am trying to print HTML table into PDF using JSPdf. My table have 20 columns. Because of that, I couldn't print the entire table. Last 4-6 column always goes hidden. Is there is anyway to make visible or bring down the hidden content ?
HTML
<div class="table-responsive" >
<table class="table table-bordered">
<thead>
<tr>
<th>Year Lease</th>
<th>user Name</th>
<th>Total Rent</th>
<th>Other Income</th>
<th>Total Income</th>
<th>Avg Expenses at 4 %</th>
<th>Value Added Expense</th>
<th>Other Expense</th>
<th>Total Expense</th>
<th>NOI</th>
<th>CAP Rate</th>
<th>Interest Paid</th>
<th>Net Income</th>
<th>Principal</th>
<th>Yearly Cashflow</th>
<th>Yearly</th>
<th>DS Ratio</th>
</tr>
</thead>
<tbody *ngFor="let userInfo of user;index as i">
<tr>
<td>Year {{i+1}} Leased</td>
<td *ngFor="let user of userInfo.user">{{user.amount | currency}}</td>
<td>{{user.grossIncome | currency}}</td>
<td>{{user.otherIncome | currency }}</td>
<td>{{user.totalIncome | currency }}</td>
<td>{{user.totalExpense}}</td>
<td>{{user.valueAddedExpense | currency}}</td>
<td>{{user.otherExpense | currency}}</td>
<td>{{user.totalExpense | currency}}</td>
<td>{{user.netOperatingIncome | currency}}</td>
<td>{{user.capRate}}% </td>
<td>{{user.mortageInterest | currency}}</td>
<td>{{user.netIncome | currency}}</td>
<td>{{user.principle | currency}}</td>
<td>{{user.yearlyCashFlow | currency}}</td>
<td>{{user.yearly}} %</td>
<td>{{user.deptServiceRatio}} %</td>
</tr>
</tbody>
</table>
</div>
TS
var pdf = new jsPDF('p','pt', 'a3');
pdf.internal.scaleFactor = 1.40;
pdf.addHTML(this.print.nativeElement, 0, 0, {
pagesplit: true
}, ()=> {
pdf.save('Report-' + new Date() + '.pdf');
});
Issue
There are still 4 more column left after CAP Rate. Please help me out
Y must set your pdf height like this:
var width = pdf.internal.pageSize.getWidth();
var height = pdf.internal.pageSize.getHeight();
Related
I just want to copy data(Item and Price) of the first table to the second table and make increment in Quantity(Second table) when i click in the First Table ( Item). I am working on Angular 9
First Table:
Code | Item | Price | Unit |
1 | Mouse | 500 | Piece |
2 | Wire | 100 | Piece |
Second Table:
Item | Quantity| Price |
1 | 2 | 1000 |
2 | 1 | 100 |
I did a lot to work with it but I could not get any required output.
It is possible to solve using javaScript/Js/jquery
<table class="table table-hover" id="firstTable">
<thead class="table-primary">
<tr>
<td>Code</td>
<td>Item</td>
<td>Unit</td>
<td>Price</td>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of itemList;" id="moveMeIntoMain"
style="cursor:pointer">
<td>{{data.itemCode}}</td>
<td>{{data.itemName}}</td>
<td><span>{{data.unitId}}</span>{{data.name}}</td>
<td>{{data.retailRate}}</td>
</tr>
</tbody>
</table>
<table class="table table-hover" id="secondTable">
<thead class="">
<tr class="table-primary">
<td>#</td>
<td>Item</td>
<td>Price</td>
<td>Quantity</td>
<td>Action</td>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
Js
$(document).ready(function () {
var items = [];
$("#firstTable tr").on("click", function () {
var newTr = $(this).closest("tr").clone();
$(newButtonHTML).children("button").click(function (e) {
});
$(newTr).children("td:last").html("");
items.push(newTr);
newTr.appendTo($("#secondTable"));
});
})
You can simply try in Angular way ;). Just add click handler to the each row and send row data
Working stackblitz
Template file
<table>
<thead>
<th>Code</th>
<th>Item</th>
<th>Price</th>
<th>Unit</th>
</thead>
<tr *ngFor="let data of firstTableData" (click)="updateSecondTable(data)">
<td>{{ data.Code }}</td>
<td>{{ data.Item }}</td>
<td>{{ data.Price }}</td>
<td>{{ data.Unit }}</td>
</tr>
</table>
<hr>
<table *ngIf="secondTableData.length">
<thead>
<th>Item</th>
<th>Quantity</th>
<th>Price</th>
</thead>
<tbody>
<tr *ngFor="let newdata of secondTableData">
<td>{{ newdata.Item }}</td>
<td>{{ newdata.Quantity }}</td>
<td>{{ newdata.Price }}</td>
</tr>
</tbody>
</table>
And in the typescript file
Declare a empty secondTableData array
And have a method, which firstly checks for the item existence in the second table array. If item already exists, then simply update quantity and price
If item doesn't exist, just push the item with required columns to the second table array
Component.ts
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
name = 'Angular ' + VERSION.major;
firstTableData = [{
Code: 1,
Item: 'Mouse',
Price: 500,
Unit: 'Piece'
},
{
Code: 2,
Item: 'Wire',
Price: 100,
Unit: 'Piece'
},
{
Code: 3,
Item: 'Some Item',
Price: 300,
Unit: 'Some Unit'
}
];
secondTableData = [];
updateSecondTable(data) {
let foundItem = this.secondTableData.find((item) => item.Item === data.Item);
if (foundItem) {
foundItem.Quantity += 1;
foundItem.Price += data.Price;
return;
}
this.secondTableData.push({
Item: data.Item,
Quantity: 1,
Price: data.Price,
})
}
}
I have an array which is created from splitting a string using str.split() and this creates an array and it looks like this:
var array = [
"TEXT1,1234,4321,9876",
"TEXT2,2345,5432",
"TEXT3,6543,3456"
]
I want to be able to display this information in a table using *ngFor.
I have tried this (from this question):
<tr>
<td *ngFor="let info of array">{{info.join(",")}}</td>
</tr>
But I get this error:
ERROR TypeError: _v.context.$implicit.join is not a function
at Object.eval [as updateRenderer]
The table should look like this:
TITLE | VALUE1 | VALUE2 | VALUE3
--------------------------------
TEXT1 | 1234 | 4321 | 9876
--------------------------------
TEXT2 | 2345 | 5432 |
--------------------------------
TEXT3 | 6543 | 3456 |
How do I achieve this table?
To make array from string with , delimiters use String.prototype.split method
<tr *ngFor="let row of array">
<td *ngFor="let info of row.split(',')">{{info}}</td>
</tr>
Ng-run Example
You will need two *ngFors. One to loop through each item in the array and one to iterate through each item in the array that you'll create by splitting the string with ,
Give this a try:
<table border="1">
<thead>
<tr>
<td>TITLE</td>
<td>VALUE 1</td>
<td>VALUE 2</td>
<td>VALUE 3</td>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of array">
<td *ngFor="let column of row.split(',')">
{{ column }}
</td>
</tr>
</tbody>
</table>
Here's a Working Sample StackBlitz for your ref.
I've got a table with large number of columns, I need to be able to show and hide some columns by clickin checkbox. I've tried a lot of variations of ng-click--ng-show, $scope$watch and now I've trying to do this by addEventListener, but It doesn't work, nothing happend.
$scope.showTheItem = false;
function newFunction() {
document.getElementById("showTheItemEvent").addEventListener('checked', function () {
$scope.showTheItem = true;
$scope.digest();
});
}
and this is html:
<form ng-show="showTheForm"> // this is the form with checkboxes
<table onload="newFunction();">
<tr><td style="vertical-align:top" ng-repeat="item in superKeys" ng-if="$even"><input type="checkbox" id="showTheItemEvent" ng-true-value="checked" style="margin-left:3px; margin-right:15px"><label>{{localization.setLicTabs[locale][item]}}</label></td></tr>
<tr style="height:10px"></tr>
<tr><td style="vertical-align:top" ng-repeat="item in superKeys" ng-if="$odd"><input type="checkbox" id="showTheItemEvent" ng-true-value="checked" style="margin-left:3px; margin-right:15px"><label>{{localization.setLicTabs[locale][item]}}</label></td></tr>
</table>
</form>
<table>
<thead>
<tr>
<th ng-show="showTheItem">{{localization.setLicTabs[locale].VirtualType}}</th>
<th ng-show="showTheItem">{{localization.setLicTabs[locale].FarmName}}</th>
</tr>
</thead>
<tbody dir-paginate="item in dataObjHosts | filter:searchFilter | orderBy:orderListType:true | itemsPerPage: pageSize" pagination-id="POPaginatorServersSoft" current-page="currentPage" ng-click="setActiveState($event)">
<tr >
<td ng-show="showTheItem"><span ng-bind="dataObj[item][0].VirtualType"></span></td>
<td ng-show="showTheItem"><span ng-bind="dataObj[item][0].FarmName"></span></td>
</tr>
I have a table that contains multiple columns and rows. When viewing on a small screen(phone) i want to hide some of those columns, otherwise show all columns.
The data inside my table is populated using a repeat. As i re-use the table in multiple places i would like to keep the repeat as the column and row count is different.
<table md-table class="md-data-table" id="data-table">
<thead md-head md-order="gridCtrl.gridModel.orderBy">
<tr md-row>
<th md-column ng-repeat="header in gridCtrl.gridModel.headers" md-order-by="fields[{{$index}}].value">
{{header.title}}
</th>
</tr>
</thead>
<tbody md-body>
<tr md-row ng-repeat="item in gridCtrl.gridModel.items | orderBy: gridCtrl.gridModel.orderBy | limitTo: gridCtrl.gridModel.itemsPerPage : (gridCtrl.gridModel.firstPage -1) * gridCtrl.gridModel.itemsPerPage">
<td md-cell ng-repeat="field in item.fields">
<div ng-if="gridCtrl.isLink(field)">
<h4 class="blue-link" id="gridFieldString{{field.value | idfy}}" ng-click="gridCtrl.click($event, field)">
{{field.value}}
</h4>
</div>
<div ng-if="!gridCtrl.isLink(field)">{{field.value}}</div>
</td>
</tr>
</tbody>
</table>
you can use
window.screen.availHeight
window.screen.availWidth
to get the current resolution.
Then add a ng-hide with screen resolution or
<tr md-row ng-hide="window.screen.availHeight < 500 && window.screen.availWidth <200">
You need to read media queries and define rules according to screen width
http://www.w3schools.com/css/css_rwd_mediaqueries.asp
i want to set a height of a element just once in angular but i dont want to use a jquery inside it.I cant use ng-style as it fires multiple times.
here is my html for that
<md-card>
<md-table-container flex>
<md-virtual-repeat-container id="vrContainerProcessFlow" ng-init="$ctrl.getMdTableContainerWidth()">
<table md-table class="md-table-striped" md-row-select="true" multiple="true" ng-model="$ctrl.selected" md-progress="$ctrl.promise">
<thead md-head fix-head md-order="modifyTs">
<tr md-row>
<th md-column md-order-by="processFlowNbr">Number</th>
<th md-column md-order-by="processFlowDesc">Name</th>
<th md-column md-order-by="ownerUserId">Created By</th>
<th md-column md-order-by="modifyUserId">Modified By</th>
<th md-column md-order-by="createTs">Created Date</th>
<th md-column md-order-by="modifyTs">Last Modified Date</th>
</tr>
</thead>
<tbody md-body>
<tr md-row md-select="processFlow" md-on-select="$ctrl.updateSelection" md-on-deselect="$ctrl.updateSelection" md-virtual-repeat="processFlow in $ctrl.processFlows | orderBy: modifyTs">
<td md-cell
ng-click="$ctrl.OnProcessFlowClick($event, processFlow)">
{{processFlow.processFlowNbr}}
<md-tooltip>Click to modify</md-tooltip>
</td>
<td md-cell>{{processFlow.processFlowNbr}}</td>
<td md-cell>{{processFlow.processFlowDesc}}</td>
<td md-cell>{{processFlow.ownerUserId}}</td>
<td md-cell>{{processFlow.modifyUserId}}</td>
<td md-cell>{{processFlow.createTs | date:'MM/dd/yyyy'}}</td>
<td md-cell>{{processFlow.modifyTs | date:'MM/dd/yyyy'}}</td>
</tr>
<tr md-row ng-if="$ctrl.processFlows.length === 0">
<td md-cell>No Records Found !</td>
</tr>
</tbody>
</table>
</md-virtual-repeat-container>
</md-table-container>
<process-flows-confirm-delete></process-flows-confirm-delete>
</md-card>
in this i m setting height for md-virtual repeat container and this mark up is wrapped up in a div with id "mdDialogProcessFlows".
This is the function for calculating the height in typescript
getMdTableContainerWidth(): void {
let style = "height: ";
let mdDialog = document.getElementById("mdDialogProcessFlows").scrollHeight;
style += mdDialog - 80 + 'px';
let mdVRContainer = angular.element(document.getElementById("vrContainerProcessFlow"));
mdVRContainer.attr("style", style);
}
does any body has any solution without using ng-style, directives and ofcourse no javascript or jquery?
You can still use ng-style with a one-time bind. This will only set the value once and doesn't call the function a second time. Use this syntax:
ng-style="::{width: getMdTableContainerWidth()}"
The :: will make the expression a one-time bind