I am currently creating a web application that allows a user to upload an excel file into a database but before the user uploads the file I would like to allow them to check the headers of the excel file if it matches the preset on the database.
The code below allows me to display everything on the excel file:
$('#inputfile').change(function(e){
var reader = new FileReader();
reader.readAsArrayBuffer(e.target.files[0]);
reader.onload = function(e) {
var data = new Uint8Array(reader.result);
var wb = XLSX.read(data,{type:'array'});
var htmlstr = XLSX.write(wb,{sheet:"Sheet1", type:'binary',bookType:'html'});
$('#printHere')[0].innerHTML += htmlstr;
}
});
I would like to only store the excel file's header in an array and display it.
I'm new to Javascript so any help would be much appreciated.
You can do something like:
const header = []
const columnCount = XLSX.utils.decode_range(ws['!ref']).e.c + 1
for (let i = 0; i < columnCount; ++i) {
header[i] = ws[`${XLSX.utils.encode_col(i)}1`].v
}
Here is the whole example:
function extractHeader(ws) {
const header = []
const columnCount = XLSX.utils.decode_range(ws['!ref']).e.c + 1
for (let i = 0; i < columnCount; ++i) {
header[i] = ws[`${XLSX.utils.encode_col(i)}1`].v
}
return header
}
function handleFile() {
const input = document.getElementById("file")
const file = input.files[0]
if (file.type !== 'application/vnd.ms-excel') {
renderError()
}
const reader = new FileReader()
const rABS = !!reader.readAsBinaryString
reader.onload = e => {
/* Parse data */
const bstr = e.target.result
const wb = XLSX.read(bstr, { type: rABS ? 'binary' : 'array' })
/* Get first worksheet */
const wsname = wb.SheetNames[0]
const ws = wb.Sheets[wsname]
const header = extractHeader(ws)
renderTable(header)
}
if (rABS) reader.readAsBinaryString(file)
else reader.readAsArrayBuffer(file)
}
function renderTable(header) {
const table = document.createElement('table')
const tr = document.createElement('tr')
for (let i in header) {
const td = document.createElement('td')
const txt = document.createTextNode(header[i])
td.appendChild(txt)
tr.appendChild(td)
}
table.appendChild(tr)
document.getElementById('result').appendChild(table)
}
function renderError() {
const errorMsg = 'Unexpected file type'
const error = document.createElement('p')
error.setAttribute('class', 'error')
const txt = document.createTextNode(errorMsg)
error.appendChild(txt)
document.getElementById('result').appendChild(error)
throw new Error(errorMsg)
}
#result table tr td {
border: 2px solid grey;
}
#result .error {
color: red;
}
<script src="https://unpkg.com/xlsx/dist/xlsx.full.min.js"></script>
<input type="file" onchange="handleFile()" id='file' accept=".csv"/>
<div id="result"><div>
Related
I need to read only visible rows from an excel file.
Now I am getting with all rows in excel file while using the following code.
let fileReader = new FileReader();
fileReader.readAsBinaryString(selectedFile);
fileReader.onload = (event) => {
let data = event.target.result;
let workbook = XLSX.read(data, { type: "binary" });
let rowObject = XLSX.utils.sheet_to_row_object_array(workbook.Sheets[workbook.SheetNames[j]]);
import * as Excel from "exceljs/dist/exceljs.min.js";
checkHiddenRowAndColumns(file) {
const workbook = new Excel.Workbook();
const arryBuffer = new Response(file).arrayBuffer();
arryBuffer.then(function (data) {
workbook.xlsx.load(data)
.then(function () {
const worksheet = workbook.getWorksheet(1);
//check hidden columns
for(var i=0; i < worksheet.columns.length; i++) {
if(worksheet.columns[i].hidden == true){
console.log('hidden columns' + i)
}
}
//check hidden rows
worksheet.eachRow(function (row,rowNumber) {
if(row.hidden == true) {
console.log('hidden row' + rowNumber)
}
});
this.spinnerService.hide();
});
});
}
onFileChange(evt: any) {
this.spinnerService.show();
this.data = [];
this.uploadedFileName = '';
/* wire up file reader */
const target: DataTransfer = <DataTransfer>(evt.target);
if (target.files.length > 1) throw new Error('Cannot use multiple files');
if (target.files.length === 1) {
this.checkHiddenRowAndColumns(target.files[0]);
this.enableImportExcel = true;
const file = target.files[0];
this.searchFilterForm.get('edt').setValue(file);
this.uploadedFileName = target.files[0].name;
if (target.files.length == 1 && (target.files[0].type == ".xlsx" || target.files[0].type == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" || target.files[0].type == "application/vnd.ms-excel")) {
const reader: FileReader = new FileReader();
reader.onload = (e: any) => {
/* read workbook */
const bstr: string = e.target.result;
const wb: XLSX.WorkBook = XLSX.read(bstr, { type: 'binary' });
/* grab first sheet */
const wsname: string = wb.SheetNames[0];
const ws: XLSX.WorkSheet = wb.Sheets[wsname];
this.data = (XLSX.utils.sheet_to_json(ws, { header: 1, raw: false }));
};
reader.readAsBinaryString(target.files[0]);
}
else {
this.enableImportExcel = false;
}
} else {
this.uploadedFileName = "";
}
}
There is skip hidden row option in sheet_to_csv method I just used it and reparse the output:
function xslxRemoveSheetHiddenRows(sheet){
let csv=XLSX.utils.sheet_to_csv(sheet,{skipHidden:true})
let filteredWorkbook=XLSX.read(csv, {type: 'binary'});
return filteredWorkbook.Sheets.Sheet1;
}
And usage example:
//loading cell's style is essential to detect hidden rows and columns
let workbook = XLSX.read(data, { type: 'binary', cellStyles: true });
//unhide the title rows to save it from elimination
workbook.Sheets.Data["!rows"][0].hidden = false;
//removing hidden rows and columns
let sheet = xslxRemoveSheetHiddenRows(workbook.Sheets.Data);
So I'm writing a simple web app that all it does is load a CSV, add an "agree?" checkbox to the end of each row, then downloads the table as CSV.
That downloaded CSV will later be converted to an SQL table, but before that, I need to find a way to give each row a boolean variable based on what the user checked or didn't check.
So here's the JS which is built out of a few functions that load a CSV, add the checkbox I mentioned, then convert it back.
function buildHeaderElement (header) {
const headerEl = document.createElement('thead')
headerEl.append(buildRowElement(header, true))
return headerEl
}
function buildRowElement (row, header) {
const columns = row.split(',')
const rowEl = document.createElement('tr')
for (column of columns) {
const columnEl = document.createElement(`${header ? 'th' : 'td'}`)
columnEl.textContent = column
rowEl.append(columnEl)
}
rowEl.append(provideeColumnAgree(row, header))
return rowEl
}
function provideeColumnAgree(row, header) {
const columnAgree = document.createElement(`${header ? 'th' : 'td'}`)
if(header)
{
columnAgree.textContent = 'Agree?';
}
else
{
const checkboxAgree = document.createElement(`input`)
checkboxAgree.setAttribute("type", "checkbox");
columnAgree.append(checkboxAgree)
}
return columnAgree
}
function populateTable (tableEl, rows) {
const rowEls = [buildHeaderElement(rows.shift())]
for (const row of rows) {
if (!row) { continue }
rowEls.push(buildRowElement(row))
}
tableEl.innerHTML= ''
return tableEl.append(...rowEls)
}
function createSubmitBtn() {
var button = document.createElement("button");
button.innerHTML = "Download CSV";
var body = document.getElementsByTagName("body")[0];
body.appendChild(button);
button.addEventListener ("click", function() {
exportTableToCSV('members.csv')
});
}
function downloadCSV(csv, filename) {
var csvFile;
var downloadLink;
// CSV file
csvFile = new Blob([csv], {type: "text/csv"});
downloadLink = document.createElement("a");
downloadLink.download = filename;
downloadLink.href = window.URL.createObjectURL(csvFile);
downloadLink.style.display = "none";
downloadLink.click();
}
function exportTableToCSV(filename) {
var csv = [];
var rows = document.querySelectorAll("table tr");
for (var i = 0; i < rows.length; i++) {
var row = [], cols = rows[i].querySelectorAll("td, th");
for (var j = 0; j < cols.length; j++)
row.push(cols[j].innerText);
csv.push(row.join(","));
}
// Download CSV file
downloadCSV(csv.join("\n"), filename);
}
function readSingleFile ({ target: { files } }) {
const file = files[0]
const fileReader = new FileReader()
const status = document.getElementById('status')
if (!file) {
status.textContent = 'No file selected.'
return
}
fileReader.onload = function ({ target: { result: contents } }) {
status.textContent = `File loaded: ${file.name}`
const tableEl = document.getElementById('csvOutput')
const lines = contents.split('\n')
populateTable(tableEl, lines)
status.textContent = `Table built from: ${file.name}`
createSubmitBtn()
}
fileReader.readAsText(file)
}
window.addEventListener('DOMContentLoaded', _ => {
document.getElementById('fileSelect').addEventListener('change', readSingleFile)
})
The HTML is quite simple
<html>
<body>
<input type="file" id="fileSelect"/>
<div id="status">Waiting for CSV file.</div>
<table id="csvOutput"></table>
<script src="script.js"></script>
</body>
</html>
Here's the link to the project: https://jsfiddle.net/95tjsom3/1/
While downloading the csv, you can check whether the column contains checkbox or not. And if it has a checkbox, whether it is checked or not. Then you can alter the contents of that particular column.
function exportTableToCSV(filename) {
var checkboxes = document.getElementsByTagName("input"); // get all checkboxes in the array
var csv = [];
var rows = document.querySelectorAll("table tr");
for (var i = 0; i < rows.length; i++) {
var row = [], cols = rows[i].querySelectorAll("td, th");
for (var j = 0; j < cols.length; j++) {
if(cols[j].innerHTML.includes('<input type="checkbox">')) {
if(checkboxes[i].checked) {
row.push("AGREE");
}
else {
row.push("NOT AGREE");
}
}
else {
row.push(cols[j].innerText);
}
}
csv.push(row.join(","));
}
// Download CSV file
downloadCSV(csv.join("\n"), filename);
}
> I am creating and downloading excel file with data that I have gotten in JSON format. Now I want to add status column in last and provide list data validation there with three specified value "rejected","sleected" and "on-hold"
downloadTableData(data, headers) {
this.dataToDownload = "";
let dataSourceLength = data.length;
let rowData = '';
for (let i = 0; i < dataSourceLength; i++) {
let line = '';
for (let key in data[i]) {
if (line != '') {
line = line + ','
}
line = line + data[i][key];
}
rowData = rowData + line + "\r\n";
}
// as of now; but based on api data, row data and column dat ashould be done
this.dataToDownload = this.dataToDownload + headers.join(',') + "\r\n" + rowData;
if (this.dataToDownload.split('\n').length - 1 >= 1) {
// const fileName = 'reports-' + new Date();
const fileName ='Upload_template.xlsx';
let anchor = document.createElement('a');
anchor.href = URL.createObjectURL(new Blob([this.dataToDownload], { type: 'text/csv' }));
anchor.download = fileName + '.csv';
// anchor.download = fileName;
// start download
anchor.click();
}
}
Here is the sample code how to apply data validation
const nameSourceRange = context.workbook.worksheets.getItem("Status").getRange("A1:A3");
let approvedListRule = {
list: {
inCellDropDown: true,
source: nameSourceRange
}
};
nameRange.dataValidation.rule = approvedListRule;
I created a gist for you to demo how to add the approved status.
https://gist.github.com/lumine2008/827ab26a65b76a5826331d960323c43b
I found the solution with the help of excel.js and file-saver.js.
import { Workbook } from 'exceljs';
import * as fs from 'file-saver';
generateExcel(list,header) {
let data:any = [];
for(let i=0;i<list.length;i++){
let arr = [list[i].requisitionId,list[i].applicationid, list[i].candidateid, list[i].unitcode];
data.push(arr);
}
console.log(data);
//Create workbook and worksheet
let workbook = new Workbook();
let worksheet = workbook.addWorksheet('Candidate Report');
//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.getColumn(3).width = 30;
data.forEach(d => {
let row = worksheet.addRow(d);
}
);
list.forEach((element,index) =>{
worksheet.getCell('E'+(+index+2)).dataValidation = {
type: 'list',
allowBlank: true,
formulae: ['"Selected,Rejected,On-hold"']
};
})
//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, 'candidate.xlsx');
})
}
`
I want to sore an image file to my local storage in order to reuse it on a different page. Im getting a picture or a file when on desktop. That should be transferred to a file and then I want to store it the onImagePicked function. I have connected that function with a button so the image should be transformed to a file and also be stored then. But somehow the func. is not called because I don't get my console.log. I suppose it could have to do something that Im just testing with pictures that come directly from my desktop and not with pictures from a device. But I don't know.
Here is my code: (The rest with getting and displaying the picture works)
import { Storage } from '#ionic/storage';
// convert base64 image into a file
function base64toBlob(base64Data, contentType) {
contentType = contentType || '';
const sliceSize = 1024;
const byteCharacters = atob(base64Data);
const bytesLength = byteCharacters.length;
const slicesCount = Math.ceil(bytesLength / sliceSize);
const byteArrays = new Array(slicesCount);
for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
const begin = sliceIndex * sliceSize;
const end = Math.min(begin + sliceSize, bytesLength);
const bytes = new Array(end - begin);
for (let offset = begin, i = 0; offset < end; ++i, ++offset) {
bytes[i] = byteCharacters[offset].charCodeAt(0);
}
byteArrays[sliceIndex] = new Uint8Array(bytes);
}
return new Blob(byteArrays, { type: contentType });
}
export const IMAGE_DATA = 'image_data';
...
#ViewChild('filePicker') filePickerRef: ElementRef<HTMLInputElement>;
#Output() imagePick = new EventEmitter<string | File>();
selectedImage: string;
usePicker = false;
...
takePicture() {
if (this.usePicker) {
this.filePickerRef.nativeElement.click();
}
Plugins.Camera.getPhoto({
quality: 80,
source: CameraSource.Prompt,
correctOrientation: true,
saveToGallery: true,
allowEditing: true,
resultType: CameraResultType.Base64,
direction: CameraDirection.Front
}).then(image => {
this.selectedImage = image.base64String;
this.imagePick.emit(image.base64String);
}).catch(error => {
console.log(error);
return false;
});
}
onImagePicked(imageData: string | File) {
let imageFile;
if (typeof imageData === 'string') {
try {
imageFile = base64toBlob(imageData.replace('data:image/jpeg;base64,', ''), 'image/jpeg');
this.storage.set('image_data', imageFile);
console.log('stored');
} catch (error) {
console.log(error);
}
} else {
imageFile = imageData;
}
}
onFileChosen(event: Event) {
const pickedFile = (event.target as HTMLInputElement).files[0];
const fr = new FileReader();
fr.onload = () => {
const dataUrl = fr.result.toString();
this.selectedImage = dataUrl;
this.imagePick.emit(pickedFile);
};
fr.readAsDataURL(pickedFile);
}
html (where I try to call the function)
<app-make-photo (imagePick)="onImagePicked($event)"></app-make-photo>
I am trying to get the type of excel file either it is macro or not.
I used XLXS library but do not get the result.
wb_has_macro(wb/*:selectedfile*/)/*:boolean*/ {
const fileReader = new FileReader();
fileReader.onload = (e) => {
const arrayBuffer = fileReader.result;
const data = new Uint8Array(arrayBuffer);
const arr = new Array();
for (let i = 0; i !== data.length; ++i) {
arr[i] = String.fromCharCode(data[i]);
}
const bstr = arr.join('');
this.workbook = XLSX.read(bstr, { type: 'binary' });
const first_sheet_name = this.workbook.SheetNames[0];
const worksheet = this.workbook.Sheets[first_sheet_name];
if (!!this.workbook.vbaraw) {
return true;
}
const sheets = this.workbook.SheetNames.map((n) =>
this.workbook.Sheets[n]);
return sheets.some((ws) => {
return !!ws && ws['!type'] === 'chart';
});
};
fileReader.readAsArrayBuffer(wb._file);}