I am using SheetJS community version in combination with the xlsx-js-style package in order to add styles to the cells.
The SheetJS part works fine, I get my Excel file as intended. But when I try to add a style to a cell (following xlsx-js-style documentation), no style is applied. I do not get any errors either.
This is what I tried (the part that doesn't work is //style A1 cell):
//define column order
var headers = ["fullname", "currentcompany", "currentjobtitle", "statusid", "location", "comments", "linkedinurl", "mobilenumber", "email"]
//create worksheet and workbook
var ws = XLSX.utils.json_to_sheet(filteredProfiles, { header: headers, origin: "A4" });
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
//add custom header names
let Heading = [['Name', 'Company', 'Title', 'Status', 'Location', 'Comments', 'Profile', 'Phone', 'Email']];
XLSX.utils.sheet_add_aoa(ws, Heading, { origin: 'A4' });
//set cols/rows width and height
ws['!cols'] = [];
ws['!rows'] = [];
ws['!cols'] = [
{ 'width': 30 }, // width for col A
{ 'width': 30 }, // width for col B
];
ws['!rows'] = [
{ 'hpt': 60 },// height for row 1
{ 'hpt': 20 },]; //height for row 2
//add title in A1
XLSX.utils.sheet_add_aoa(ws, [
["Recent profiles"]
], { origin: "A1" });
//define current date
let today = new Date();
let dd = String(today.getDate()).padStart(2, '0');
let MM = String(today.getMonth() + 1).padStart(2, '0');
let yyyy = today.getFullYear();
//add current date in A2
XLSX.utils.sheet_add_aoa(ws, [
[`${dd}/${MM}/${yyyy}`]
], { origin: "A2" });
//style A1 cell
ws["A1"].s = {
font: {
name: "Calibri",
sz: 24,
bold: true,
color: { rgb: "FFFFAA00" },
},
};
//generate XLSX file and trigger a download
XLSX.writeFile(wb, "data.xlsx");
I found out that I was missing const XLSX = require('sheetjs-style'); before the code I posted. Now it works.
Related
i want to create a pdf report using jspdf but i have a problem with the table and image overlay one to the others. Also it happens with the text that i want to insert in the report. how can i resolve it?
this is code where i am creating the report:
imprimir() {
const doc = new jsPDF({
orientation: "portrait",
unit: "px",
format: "A4",
});
const encabezado = [
"Name",
"Calories",
"Fat",
"Carbs",
"Proteins",
"Iron",
];
const titulo = "ORDER DE TRABAJO - TALLERES DE TERCEROS";
doc.text(titulo, doc.internal.pageSize.width * 0.5, 100, {
aling: "right",
});
const arregloDatos = Object(this.desserts).map(function (obj) {
const datos = [
obj.name,
obj.calories,
obj.fat,
obj.carbs,
obj.protein,
obj.iron,
];
return datos;
});
autoTable(doc, {
head: [encabezado],
body: arregloDatos,
});
const logo = require("../assets/Logo_edese_hd(2).png");
var imgLogo = new Image();
imgLogo.src = logo;
doc.addImage(imgLogo, "PNG", 0, 0, 200, 80);
const hoy = new Date();
doc.save(
hoy.getDate() +
hoy.getMonth() +
hoy.getFullYear() +
hoy.getTime() +
".pdf"
);
}
I have one download button and table that store user data in user.component.html file and when user clicks on the download button then it exports all the table's data into an Excel file.
I want to display a loading spinner when the download takes longer than 1.5 seconds to start.
I am using angular 8.
user.component.html file:
<div class ="container">
<button (click)="generateExcel()">
Generate Excel</button>
<table>
-----table related data
<\table>
</div>
user.component.ts file:
generateExcel() {
//Excel Title, Header, Data
const title = 'Car buyers Report';
const header = ["Year", "Month", "User", "Model"]
const data = [
[2007, 1, "jo", "Volkswagen Passat"],
[2007, 1, "mike ", "Toyota Rav4"],
[2007, 1, "david", "Toyota Avensis"],
[2007, 1, "milenda ", "Volkswagen Gol"]
];
//Create workbook and worksheet
let workbook = new Workbook();
let worksheet = workbook.addWorksheet('Car Data');
//Add Row and formatting
let titleRow = worksheet.addRow([title]);
titleRow.font = { name: 'Comic Sans MS', family: 4, size: 16, underline: 'double', bold: true }
worksheet.addRow([]);
let subTitleRow = worksheet.addRow(['Date : ' + this.datePipe.transform(new Date(), 'medium')])
//Add Image
let logo = workbook.addImage({
base64: logoFile.logoBase64,
extension: 'png',
});
worksheet.addImage(logo, 'E1:F3');
worksheet.mergeCells('A1:D2');
//Blank Row
worksheet.addRow([]);
//Add Header Row
let headerRow = worksheet.addRow(header);
// Cell Style : Fill and Border
headerRow.eachCell((cell, number) => {
cell.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFFFFF00' },
bgColor: { argb: 'FF0000FF' }
}
cell.border = { top: { style: 'thin' }, left: { style: 'thin' }, bottom: { style: 'thin' }, right: { style: 'thin' } }
})
// worksheet.addRows(data);
// Add Data and Conditional Formatting
data.forEach(d => {
let row = worksheet.addRow(d);
let qty = row.getCell(5);
let color = 'FF99FF99';
if (+qty.value < 500) {
color = 'FF9999'
}
qty.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: color }
};
});
worksheet.getColumn(3).width = 30;
worksheet.getColumn(4).width = 30;
worksheet.addRow([]);
//Footer Row
let footerRow = worksheet.addRow(['This is system generated excel sheet.']);
footerRow.getCell(1).fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFCCFFE5' }
};
footerRow.getCell(1).border = { top: { style: 'thin' }, left: { style: 'thin' }, bottom: { style: 'thin' }, right: { style: 'thin' } }
//Merge Cells
worksheet.mergeCells(`A${footerRow.number}:F${footerRow.number}`);
//Generate Excel File with given name
workbook.xlsx.writeBuffer().then((data) => {
let blob = new Blob([data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
fs.saveAs(blob, 'CarData.xlsx');
})
}
I imagine your writeBuffer call is what takes you the most time.
As writeBuffer is asynchronous, you could use rxjs observables which allow you to have more complex behaviors than a classic async/await.
First convert your promise to an observable :
// here you have a promise
const wBufferPromise = workbook.xlsx.writeBuffer();
// and here you have an observable, hence the $ char in the variable name
const wBufferObservable = from(wBufferPromise );
You can then probably user timeoutWith from RxJS (which i never used so I won't be able to help you here.
Another possible solution would be to call setTimeout(myFunc,1500) where myFunc sets your spinner visibility if needed.
Edit :
Please have a look at Eliseo's comment.
I want to put thick border in all my cells. this is an angular project, I am using typescript.
I can do this for 1 cell,
worksheet.getCell('A1').border = {
top: { style: 'thick' },
left: { style: 'thick' },
bottom: { style: 'thick' },
right: { style: 'thick' }
};
But I want to do something like 2 nested for loops . For each row , make each cell thick
Here is I tried : app.component.ts
import { Component, OnInit } from '#angular/core';
import { DataService } from '../data.service';
import * as jspdf from 'jspdf';
import html2canvas from 'html2canvas';
// import * as XLSX from 'xlsx';
import * as ExcelJS from 'exceljs';
import * as FileSaver from 'file-saver';
import { ViewChild, ElementRef } from '#angular/core';
#Component({
selector: 'app-items-report',
templateUrl: './items-report.component.html',
styleUrls: ['./items-report.component.css']
})
export class ItemsReportComponent implements OnInit {
purchases: any;
constructor(private dataService: DataService) {
this.GetPurchases();
}
ngOnInit(): void {
}
async GetPurchases() {
const response = await this.dataService.GetPurchases();
const dataService = await response.json();
this.purchases = dataService;
}
downloadPDF() {
const data = document.getElementById('purchaseTable'); // Id of the table
html2canvas(data).then(canvas => {
// Few necessary setting options
const imgWidth = 208;
const pageHeight = 295;
const imgHeight = canvas.height * imgWidth / canvas.width;
const heightLeft = imgHeight;
const contentDataURL = canvas.toDataURL('image/png');
// Your 1st parameter (landscape [l] or portrait [p]) determines what becomes the width and the height.
const pdf = new jspdf('p', 'mm', 'a4'); // A4 size page of PDF
const position = 0;
/* addImage explained below:
param 1 -> image in code format
param 2 -> type of the image. SVG not supported. needs to be either PNG or JPEG.
all params are specified in integer
param 3 -> X axis margin from left
param 4 -> Y axis margin from top
param 5 -> width of the image
param 6 -> height of the image
*/
// pdf.addImage(contentDataURL, 'PNG', 0, position, imgWidth, imgHeight);
// pdf.addImage(contentDataURL, 'PNG', 18, 30, imgWidth - 17, imgHeight);
pdf.addImage(contentDataURL, 'PNG', 18, 30, imgWidth - 21, imgHeight);
pdf.save('MYPdf.pdf'); // Generated PDF
});
}
downloadExcel() {
const date = new Date().toISOString().slice(0, 10).split('-').reverse().join('/');
console.log(date);
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('My Sheet');
worksheet.columns = [
{ header: 'Id', key: 'id', width: 10},
{ header: 'Name', key: 'name', width: 32 },
{ header: 'Quantity', key: 'quantity', width: 15 },
{ header: 'Rate', key: 'rate', width: 15 },
{ header: 'Date', key: 'date', width: 15 },
{ header: 'Total', key: 'total', width: 15 }
];
for (const purchase of this.purchases) {
worksheet.addRow({
id: purchase.item_id ,
date: purchase.item_purchase_date.toString().slice(0, 10).split('-').reverse().join('/'),
name: purchase.item_name,
quantity: purchase.item_quantity,
rate: purchase.item_rate,
total: purchase.item_rate * purchase.item_quantity
})
.alignment = { horizontal: 'left' };
}
worksheet.getRow(1).font = { bold: true };
// Iterate over all rows (including empty rows) in a worksheet
worksheet.eachRow({ includeEmpty: true }, (row, rowNumber) => {
console.log('Row ' + rowNumber + ' = ' + JSON.stringify(row.values));
row.eachCell({ includeEmpty: true }, (cell, rowNumber) => {
// ...please make my cell thick here
// i cant no longer write a1 or b1
// i need to access all cells - including empty cells
});
});
book.xlsx.readFile('export.xlsx');
}
I need to make each of my cells thick, inside for loop. So please help me how to access each cell in a loop without writing a1 or b1
Worksheet gives you a columns property on which you can iterate and use it like :-
worksheet.columns.forEach(column => {
column.border = {
top: { style: "thick" },
left: { style: "thick" },
bottom: { style: "thick" },
right: { style: "thick" }
};
});
To put border in all cells :-
exceljs version 1.12.0
worksheet.columns.forEach((col) => {
col.style.font = { name: 'Comic Sans MS' };
col.style.border = { top: { style: 'thin' }, left: { style: 'thin' }, bottom: { style: 'thin' }, right: { style: 'thin' } };
})
I tried the code like this with many small restructuration and modification but without success.
Here is the code:
$(function () {
$.get('data.csv', function(data) {
// split the data set into ohlc and volume
var ohlc = [],
volume = [],
dataLength = data.length,
// set the allowed units for data grouping
groupingUnits = [[
'week', // unit name
[1] // allowed multiples
], [
'month',
[1, 2, 3, 4, 6]
]],
i = 0;
for (i; i < dataLength; i += 1) {
ohlc.push([
data[i][0], // the date
data[i][1], // open
data[i][2], // high
data[i][3], // low
data[i][4] // close
]);
volume.push([
data[i][0], // the date
data[i][5] // the volume
]);
}
$('#chart').highcharts({
rangeSelector: {
selected: 1
},
title: {
text: 'AAPL Historical'
},
yAxis: [{
labels: {
align: 'right',
x: -3
},
title: {
text: 'OHLC'
},
height: '60%',
lineWidth: 2
}, {
labels: {
align: 'right',
x: -3
},
title: {
text: 'Volume'
},
top: '65%',
height: '35%',
offset: 0,
lineWidth: 2
}],
data: {
csv: data
},
series: [{
type: 'candlestick',
name: 'AAPL',
data: ohlc,
dataGrouping: {
units: groupingUnits
}
}, {
type: 'column',
name: 'Volume',
data: volume,
yAxis: 1,
dataGrouping: {
units: groupingUnits
}
}]
});
});
});
Here is data.csv:
Date,Open,High,Low,Close,Volume
2013-12-20,9371.08,9413.09,9352.98,9400.18,161686900
2013-12-19,9279.68,9351.9,9257.24,9335.74,98276500
2013-12-18,9145.35,9190.73,9122.05,9181.75,82342700
2013-12-17,9142.75,9161.8,9085.12,9085.12,72207500
2013-12-16,9004.62,9187.78,8997.75,9163.56,99105600
2013-12-13,9016.78,9046.63,8990.58,9006.46,67761700
2013-12-12,9032.67,9060.54,8984.28,9017,75120200
2013-12-11,9093.26,9153.14,9065.51,9077.11,64845800
2013-12-10,9180.29,9223.73,9091.97,9114.44,74363400
Can you help me to figure out the problem or purpose new approch please ?
What is my goal ?
Is to be able to load a CSV file inside the chart instead of using JSON file.
Why ?
Because modifing CSV file is more easier for me using PHP than JSON, and it's for performance too.
Thank's
When you do data.length, you are getting length of the csv file string. What you need to do is split the data with the newline delimiter.
// sample from data
var data = `Date,Open,High,Low,Close,Volume
2013-12-20,9371.08,9413.09,9352.98,9400.18,161686900
2013-12-19,9279.68,9351.9,9257.24,9335.74,98276500`;
// split by \n (new line)
data = data.split('\n'); // now data is an array of rows
var finalObj = [];
// iterate over the rows
data.map(function(row){
var obj = {};
// row is a string separated by ','
row = row.split(','); // now row is an array
obj['date'] = row[0];
obj['open'] = row[1];
obj['high'] = row[2];
obj['low'] = row[3];
obj['close'] = row[4];
obj['volume'] = row[5];
finalObj.push(obj);
})
console.log(finalObj);
Output:
[
{
date:'Date',
open:'Open',
high:'High',
low:'Low',
close:'Close',
volume:'Volume'
},
{
date:'2013-12-20',
open:'9371.08',
high:'9413.09',
low:'9352.98',
close:'9400.18',
volume:'161686900'
},
{
date:'2013-12-19',
open:'9279.68',
high:'9351.9',
low:'9257.24',
close:'9335.74',
volume:'98276500'
}
]
I created a simple app which have table and chart with date filters. There's 4 choices. Today, Yesterday, This Month, and Last Month, and one Submit button. It's working perfectly when page load. The table show list all of model and the chart show data what I want expected, perfect.
When I choosed a choice (for example : This Month) and click submit for first time, table and chart is refreshing, perfect.
But when I choosed for second time, It's give me error, and page is freeze
pikaday.js:70 Uncaught RangeError: Maximum call stack size exceeded.
Here's my part code
chartView.on("form:filter", function(data){
var criterion = data
filteredData.filter(criterion)
data1 = filteredData.filter(criterion)
chartView.trigger("view:render");
})
Here's full part code
programming.module("Program.Chart",function(Chart, programming, Backbone, Marionette, $, _){
Chart.Controller = {
getData : function(){
var data1 = programming.request("data:entities");
if(data1 !== undefined){
var filteredData = programming.Program.FilteredCollection({
collection : data1,
filterFunction : function(criterion){
return function(data){
var dateModel = moment(data.get("tanggal"),'DD/MM/YYYY');
var startDate = moment(criterion.date1,'DD/MM/YYYY')
var endDate = moment(criterion.date2,'DD/MM/YYYY')
if(dateModel.isSameOrAfter(startDate)){
if(dateModel.isSameOrBefore(endDate)){
return data
}
}
}
}
})
chartView = new Chart.chartV({
collection: filteredData
})
chartView.on("form:filter", function(data){
var criterion = data
filteredData.filter(criterion)
data1 = filteredData.filter(criterion)
chartView.trigger("view:render");
})
chartView.on("view:render", function(){
//DatePicker
var format = "DD/MM/YYYY"
var date1 = new Pikaday({
field : $("#date1",this.el)[0],
format : format
})
$("#date1",this.el)[0].value = moment().add('days').format(format)
var date2 = new Pikaday({
field : $("#date2",this.el)[0],
format : format
})
$("#date2",this.el)[0].value = moment().add('days').format(format)
var selectdate = $('#publicdate',this.el)[0];
selectdate.addEventListener("change",function(){
var value = selectdate.value;
var date1 = $('#date1',this.el)[0];
var date2 = $('#date2',this.el)[0];
if(value==="today"){
date1.value = moment().add('days').format(format)
date2.value = moment().add('days').format(format)
$(date1).attr('disabled',true);
$(date2).attr('disabled',true);
} else if(value==="yesterday"){
date1.value = moment().add(-1,'days').format(format)
date2.value = moment().add(-1,'days').format(format)
$(date1).attr('disabled',true);
$(date2).attr('disabled',true);
} else if(value==="thismonth"){
date1.value = moment().add('month').startOf('month').format(format)
date2.value = moment().add('month').endOf('month').format(format)
$(date1).removeAttr('disabled',true);
$(date2).removeAttr('disabled',true);
} else if(value==="lastmonth"){
date1.value = moment().add(-1,'month').startOf('month').format('DD/MM/YYYY')
date2.value = moment().add(-1,'month').endOf('month').format('DD/MM/YYYY')
$(date1).attr('disabled',true);
$(date2).attr('disabled',true);
}
})
//Chartist JS
var labels = data1.models.map(function(model){
return model.get("tanggal");
})
var tshirtv = [];
var casev = [];
var tanggal = [];
var series = data1.models.map(function(model,index){
tanggal[index] = model.get("tanggal");
if(model.get("produk")==="T-Shirt"){
tshirtv[index] = model.get("jumlah");
casev[index] ="0";
} else if(model.get("produk")==="Case"){
casev[index] = model.get("jumlah");
tshirtv[index] ="0";
}
})
tshirtv = tshirtv.filter(()=>true)
casev = casev.filter(()=>true)
var series = [
{
name : "T-shirt",
data : tshirtv
},
{
name : "Case",
data : casev
}
]
//Line Chart
var data = {
labels : labels,
series : series
}
var option = {
showArea : true,
lineSmooth : false,
showPoint : true,
chartPadding : {
bottom:60,
top:60,
},
axisX : {
showGrid:false,
},
axisY : {
onlyInteger : true,
},
plugins : [
Chartist.plugins.ctAxisTitle({
axisX: {
axisClass: 'ct-axis-title',
offset: {
x: 0,
y: 50
},
textAnchor: 'middle'
},
axisY: {
axisTitle: 'Jumlah Penjualan',
axisClass: 'ct-axis-title',
offset: {
x: 0,
y: 0
},
textAnchor: 'middle',
flipTitle: false
}
}),
Chartist.plugins.ctPointLabels({
textAnchor : "middle"
}),
Chartist.plugins.legend()
]
}
//Donut Chart
var data2 = {
labels : ['T-Shirt', 'Case'],
series : [12,23]
}
var option2 = {
chartPadding : {
top : 0,
},
labelInterpolationFnc : function(value,series){
return value + ": " +data2.series[series].value
},
donut:true,
donutWidth : 60,
plugins : [
Chartist.plugins.legend()
]
}
new Chartist.Line($('.statistic',this.el)[0],data,option)
//new Chartist.Pie($('.statistic2',this.el)[0],data2,option2)
})
programming.wrapper.show(chartView)
} else {
chartView = new Chart.notfound()
programming.wrapper.show(chartView)
}
}
}
})