First value is missing in excel file in XLSX JS - javascript

I am trying to read excel file in Javascript with the plugin xlsx.js . I can read all cell values except the first value. Here is my code:
let numArr = [];
selectFile(event) {
let reader = new FileReader();
reader.onload = () => {
const data = reader.result;
const workbook = XLSX.read(data, {
type: 'binary'
});
workbook.SheetNames.forEach((sheetName) => {
// Here is your object
const XL_row_object = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName]);
// var json_object = JSON.stringify(XL_row_object);
for (let i = 0; i < XL_row_object.length; i++) {
// this.groupNumsArr.push(XL_row_object[i]['number']);
const theNum = Object.values(XL_row_object[i])[0].toString();
numArr.push(theNum);
}
});
};
reader.readAsBinaryString(event.target.files[0]); }

The api gives first row as key so You can try this
for (let i = 0; i < XL_row_object.length; i++) {
var theNum = '';
if(i == 0)
{
theNum = Object.keys(XL_row_object[i])[0].toString();
numArr.push(theNum);
}
// this.groupNumsArr.push(XL_row_object[i]['number']);
theNum = Object.values(XL_row_object[i])[0].toString();
numArr.push(theNum);
}

Related

Uploading multiple images does not get added to FormData

I have method which detects files (in this case images):
detectFiles(event) {
this.formData = new FormData();
this.urls = [];
this.files = event.target.files;
if (this.files) {
for (const file of this.files) {
const reader = new FileReader();
reader.onload = (e: any) => {
this.urls.push(e.target.result);
};
reader.readAsDataURL(file);
}
}}
the files I've got are saved in this.files and on submit button I do this:
submitForm(value: any) {
if (value) {
this.formData.append('Title', value.title);
this.formData.append('Date', value.date);
for (let i = 0; i < this.files.length; i++) {
const chosenFileName = this.files[i].name;
const chosenFile = this.files[i];
this.formData.append('file', chosenFileName, chosenFile);
}
this.authService.uploadFile(this.formData)
.subscribe(
(response) => {
},
(error) => {
}
);
}}
here, I add values from input and then go through loop to add all the files I've got.
In the example, I added to pictures, however they did not appear in the request.
What am I doing wrong here?
The mistake was a dummy one:
for (let i = 0; i < this.files.length; i++) {
const chosenFileName = this.files[i].name;debugger;
const chosenFile = this.files[i];
this.formData.append('file', chosenFile); // <----- changed this line
}

Populate XML table after filling it in JavaScript Controller

I have an empty XML table in my SAPUi5 application:
<m:Table id="testdata3"></m:Table>
In my JavaScript controller, I use the SheetJS library to upload an Excel file and then read the data into the table, using "sheet_to_html".
When debugging my code I have all the data together and also my console.log call shows me data in the innerHTML of my table. But for some reason, the table stays empty. So basically nothing happens in the front-end. I feel like I'm missing a "return" or "populate" or something in that direction to load the table with the new data.
Any ideas?
_import : function(file) {
var oTable = this.getView().byId('testdata3');
if(file && window.FileReader){
var reader = new FileReader();
var result = {}, data;
reader.readAsBinaryString(file);
reader.onload = function(e) {
var rawLog = reader.result;
data = e.target.result;
var wb = XLSX.read(data, {type: 'binary'});
var first_sheet_name = wb.SheetNames[0];
var worksheet = wb.Sheets[first_sheet_name];
oTable.innerHTML = XLSX.utils.sheet_to_html(worksheet);
console.log(oTable.innerHTML);
}
Update: code for model
_import : function(file) {
var oTable = this.getView().byId('testdata3');
if(file && window.FileReader){
var reader = new FileReader();
var result = {}, data;
var that = this;
reader.readAsBinaryString(file);
reader.onload = function(e) {
var rawLog = reader.result;
data = e.target.result;
var wb = XLSX.read(data, {type: 'binary'});
var first_sheet_name = wb.SheetNames[0];
var worksheet = wb.Sheets[first_sheet_name];
var oModel = new sap.ui.model.json.JSONModel();
sap.ui.getCore().setModel(oModel,'myResultModel');
that.getView().byId("testdata3").setModel(oModel);
var oColumns = [];
*// I'm iterating over the column names and pushing them to my table works fine, but I'm then stuck with proceeding and pushing the rest of the data to my table..*
var cells = Object.keys(worksheet);
for (var i = 0; i < Object.keys(cells).length; i++) {
if( cells[i].indexOf('1') > -1)
{
oColumns.push(worksheet[cells[i]].v);
}
}
var oColumnNames = [];
$.each(oColumns, function(i, value) {
oColumnNames.push({
Text: oColumns[i]
});
});
oModel.setProperty("/columnNames", oColumnNames);
oModel.setProperty("/columnNames", oColumnNames);
var oTemplate = new Column({
header: new Label({
text: "{Text}"
})
});
oTable.bindAggregation("columns", "/columns", oTemplate);
};
};
},
EDIT here is an other attempt I tried, when debugging everything looks fine but the table stays empty anyways..
onXLSXupload : function(e) {
this._import(e.getParameter("files") && e.getParameter("files")[0]);
},
_import : function(file) {
console.log(file);
var oTable = this.getView().byId('testdata3');
if(file && window.FileReader){
var reader = new FileReader();
var result = {}, data;
var that = this;
reader.readAsBinaryString(file);
reader.onload = function(e) {
var rawLog = reader.result;
data = e.target.result;
var wb = XLSX.read(data, {type: 'binary'});
var first_sheet_name = wb.SheetNames[0];
var worksheet = wb.Sheets[first_sheet_name];
wb.SheetNames.forEach(function(first_sheet_name) {
var roa = XLSX.utils.sheet_to_json(wb.Sheets[first_sheet_name]);
if(roa.length > 0){
result[first_sheet_name] = roa;
}
});
var data = result[Object.keys(result)[0]];
for(var i=0; i<data.length; i++){
var excelRows = new sap.m.ColumnListItem({cells:[
new sap.m.Text({text: data[i][Object.keys(data[i])[0]]}),
new sap.m.Text({text: data[i][Object.keys(data[i])[1]]})
]});
that.getView().byId("testdata3").addItem(excelRows );
}
};
};
},
I'm simply struggling to find the right approach of binding the items to my table.. I'm wondering if it has something to do with my XML view or the controller file..
Update with answer from #MatthijsMennen Now still struggling because the items are only populated in one column
_import : function(file) {
var oTable = this.getView().byId('testdata3');
if(file && window.FileReader){
var reader = new FileReader();
var result = {}, data;
var that = this;
reader.readAsBinaryString(file);
reader.onload = function(e) {
var rawLog = reader.result;
data = e.target.result;
var wb = XLSX.read(data, {type: 'binary'});
var first_sheet_name = wb.SheetNames[0];
var worksheet = wb.Sheets[first_sheet_name];
var aColumns = that.getColumnNames(worksheet);
var aData = that.getRowData(worksheet, result);alert(aData);
var oModel = new sap.ui.model.json.JSONModel();
oModel.setData({
columns: aColumns,
rows: aData
});
oTable.setModel(oModel);
oTable.bindAggregation("columns", "/columns", function(index, context) {
return new sap.m.Column({
header: new sap.m.Label({
text: context.getObject().columnId
})
});
});
oTable.bindAggregation("items", "/rows", function(index, context){
return new sap.m.ColumnListItem({
cells: [
new sap.m.Text({text: context.getObject().cellId })
]
});
});
};
};
},
getColumnNames: function(worksheet) {
var oColumns = [];
var cells = Object.keys(worksheet);
for (var i = 0; i < Object.keys(cells).length; i++) {
if (cells[i].indexOf("1") > -1) {
var columnName = worksheet[cells[i]].v;
oColumns.push({
columnId: columnName
});
}
}
return oColumns;
},
getRowData: function(worksheet, result) {
var roa = XLSX.utils.sheet_to_json(worksheet);
if(roa.length > 0){
result[worksheet] = roa;
}
var data = result[Object.keys(result)[0]];
console.log(data.length);
var i; var x;
var oCells = []
for(i = 0; i < data.length; i++){
for(var x = 0; x < data.length; x ++) {
var excelRows = data[i][Object.keys(data[i])[x]];
console.log(data[i][Object.keys(data[i])[x]])
oCells.push({ cellId: excelRows});
}
}
return oCells;
},
update with for loop for columnlistitems
oTable.bindAggregation("items", "/rows", function(index, context) {
var roa = XLSX.utils.sheet_to_json(worksheet);
if(roa.length > 0){
result[worksheet] = roa;
}
for(var i = 0; i < roa.length; i++){
return new sap.m.ColumnListItem({
cells: [
new Text({ text :context.getObject().cellId })
]
})
};
});
I created a small example here with SheetJS. The column names get extracted from the worksheet, but you still need to get the rows from the worksheet. I added some dummy data for the rows.
Hope this helps.
View
<Table id="testdata3" />
<u:FileUploader change="onChange" buttonText="Upload" />
Controller
onChange: function(oEvent) {
var file = oEvent.getParameter("files")[0];
var oTable = this.byId("testdata3");
var reader = new FileReader();
var that = this;
reader.readAsBinaryString(file);
reader.onload = function(e) {
var data = e.target.result;
var wb = XLSX.read(data, {
type: "binary"
});
var firstSheetName = wb.SheetNames[0];
var worksheet = wb.Sheets[firstSheetName];
var oModel = new sap.ui.model.json.JSONModel();
var aColumns = that.getColumnNames(worksheet);
var aData = that.getRowData(worksheet);
var aCells = that.getCells(aColumns);
oModel.setData({
columns: aColumns,
rows: aData
});
oTable.setModel(oModel);
oTable.bindAggregation("columns", "/columns", function(index, context) {
return new sap.m.Column({
header: new sap.m.Label({
text: context.getObject().columnId
})
});
});
oTable.bindAggregation("items", "/rows", new sap.m.ColumnListItem({
// CHANGE ACCORDINGLY OR MAKE DYNAMIC
cells: aCells
}));
};
},
getColumnNames: function(worksheet) {
var oColumns = [];
var cells = Object.keys(worksheet);
for (var i = 0; i < Object.keys(cells).length; i++) {
if (cells[i].indexOf("1") > -1) {
var columnName = worksheet[cells[i]].v;
oColumns.push({
columnId: columnName
});
}
}
return oColumns;
},
getRowData: function() {
var aItems = [];
// DO YOUR THING HERE
aItems[0] = {
value0: "testvalue0",
value1: "testvalue1",
value2: "testvalue2",
value3: "testvalue3",
value4: "testvalue4"
};
return aItems;
},
getCells: function(aColumns) {
var cells = [];
for (var i = 0; i < aColumns.length; i++) {
cells[i] = new sap.m.Text({
text: "{value" + i + "}"
});
}
return cells;
}
Excel example
In one of my projects I needed to create table dynamically from controller.
Here is how I did hoping it helps you:
VIEW
<Table id="tableTask"
inset="false">
<headerToolbar>
<OverflowToolbar id="otbSubheader">
<ToolbarSpacer/>
<SearchField id="taskSearchBox" search="onSearchOrClearPressed" liveChange="onSearchTasks" showSearchButton="false">
<layoutData><OverflowToolbarLayoutData minWidth="200px" maxWidth="300px" shrinkable="true"/></layoutData>
</SearchField>
</OverflowToolbar>
</headerToolbar>
<columns>
<!-- Columns created in controller -->
</columns>
<items>
<ColumnListItem id="columnsListItemTask" press="onPressListItem" type="Navigation">
<cells>
<!-- Cells created in controller -->
</cells>
</ColumnListItem>
</items>
</Table>
CONTROLLER
onInit: function(){
...
// Get columns aggregation of table
let oColumns = this.getView().byId('columnsListItemTask');
// Define table cells
let cellToAdd1 = new sap.m.Text('textCell1',{
text: "{path/to/modelValue1}"
});
let cellToAdd2 = new sap.m.Text('textCell2',{
text: "{path/to/modelValue2}"
});
let cellToAdd3 = new sap.m.Text('textCell3',{
text: "{path/to/modelValue3}"
});
let cellToAdd4 = new sap.m.Text('textCell4',{
text: "{path/to/modelValue4}"
});
// Add cells (in this case 4 columns)
oColumns.addCell(cellToAdd1);
oColumns.addCell(cellToAdd2);
oColumns.addCell(cellToAdd3);
oColumns.addCell(cellToAdd4);
var jsonModel = new JSONModel(yourModel);
this.getView().setModel(jsonModel);
// Get Table by id
let oTable = this.getView().byId('tableTask');
oTable.removeAllItems(); //Remove old items if present
oTable.removeAllAggregation(); //Remove aggregations
oTable.bindAggregation('items', {
path:'/rowsData', // field name of you JSONModel containing data rows
template: oColumns, // rowTemplate of cells
});
...
}
UPDATE
You can do a for loop to add dynamically any number of columns:
onInit: function(){
...
// Get columns aggregation of table
let oColumns = this.getView().byId('columnsListItemTask');
let cellToAdd;
// This for loop in each columns I need to generate
// (in my case they are defined in a database and I get it with AJAX request)
for(let key in allCellsToGenearte){
cellToAdd = new sap.m.Text({
text: allCellsToGenearte["modelPath"]
});
oColumns.addCell(cellToAdd);
}
// Get Table by id
let oTable = this.getView().byId('tableTask');
oTable.removeAllItems(); //Remove old items if present
oTable.removeAllAggregation(); //Remove aggregations
oTable.bindAggregation('items', {
path:'/rowsData', // field name of JSON Model containing data rows
template: oColumns, // rowTemplate of cells
});
...
}

Javascript - FileReader how can I read and process each file at a time among multiple files

I am trying let the user drop multiple excel file and extract desired values from each one of the files and upload it to website ONE FILE AT A TIME.
My code is not working, and I am assuming this is because of the callback problem..
Could anybody help?
Edit: I also added my uploadFile function. I very much appreciate your help.
for(var i = 0; i < fileList.length; i++) {
//console.log(fileList[i]["file"]);
var reader = new FileReader();
var f = fileList[i]["file"];
//var fName = fileList[i]["fileName"];
var excelObject = fileList[i];
reader.onload = function(ev) {
var data = ev.target.result;
if(!rABS) data = new Uint8Array(data);
var wb = XLSX.read(data, {type: rABS ? 'binary' : 'array'});
var einAddress = "B3";
var engCodeAddress = "B1";
var goAddress = "B2";
var errMsg = tabName + " tab or required value is missing";
// Worksheet with the necessary info
try{
var ws = wb.Sheets[tabName];
var ein_cell = ws[einAddress];
ein = (ein_cell ? ein_cell.v.toString() : undefined);
var eng_cell = ws[engCodeAddress];
engCode = (eng_cell ? eng_cell.v.toString() : undefined);
var go_cell = ws[goAddress];
goLocator = (go_cell ? go_cell.v.toString() : undefined);
if(ein == undefined || engCode == undefined || goLocator == undefined){
hasValues = false;
}
excelObject["EngagementCode"] = engCode;
excelObject["GoSystem"] = goLocator;
excelObject["EIN"] = ein;
if(hasValues && isValid){
uploadFile(fileList[i], userInfo);
} else {
noValueErrorHandler(errMsg);
}
} catch(err){
hasValues = false;
}
};
if(rABS) reader.readAsBinaryString(f); else reader.readAsArrayBuffer(f);
}
function uploadFile(f, userInfo) {
// Define the folder path for this example.
var serverRelativeUrlToFolder = listName;
// Get info of the file to be uploaded
var file = f;
var fileInput = file["file"];
var newName = file["fileName"];
var ein = file["EIN"];
var engCode = file["EngagementCode"];
var email = userInfo;
var goLocator = file["GoSystem"];
console.log("file: " + file);
// Get the server URL.
var serverUrl = _spPageContextInfo.siteAbsoluteUrl + "/StatusTracker";
// Initiate method calls using jQuery promises.
// Get the local file as an array buffer.
var getFile = getFileBuffer(fileInput);
getFile.done(function (arrayBuffer) {
// Add the file to the SharePoint folder.
var addFile = addFileToFolder(arrayBuffer, newName);
addFile.done(function (file, status, xhr) {
// Get the list item that corresponds to the uploaded file.
var getItem = getListItem(file.d.ListItemAllFields.__deferred.uri);
getItem.done(function (listItem, status, xhr) {
// Change the display name and title of the list item.
var changeItem = updateListItem(listItem.d.__metadata);
changeItem.done(function (data, status, xhr) {
processedCount += 1;
if (processedCount < fileCount) {
uploadFile(fileList[processedCount], email);
} else if (processedCount == fileCount){
$("#dropbox").text("Done, drop your next file");
$("#ADMNGrid").data("kendoGrid").dataSource.read();
fileList = [];
alert("Total of " + processedCount + " items are processed!");
}
// Refresh kendo grid and change back the message and empty fileList
//$("#dropbox").text("Drag your Fund/Lower Tier workpaper here ...");
//location.reload(true);
});
changeItem.fail(onError);
});
getItem.fail(onError);
});
addFile.fail(onError);
});
getFile.fail(onError);
You might put the whole thing into an async function and await a Promise for each iteration, forcing the files to be processed in serial. You didn't post your uploadFile, but if you have it return a Promise that resolves once it's done, you could do the following:
async fn() {
for (var i = 0; i < fileList.length; i++) {
await new Promise((resolve, reject) => {
//console.log(fileList[i]["file"]);
var reader = new FileReader();
var f = fileList[i]["file"];
//var fName = fileList[i]["fileName"];
var excelObject = fileList[i];
reader.onload = function(ev) {
var data = ev.target.result;
if (!rABS) data = new Uint8Array(data);
var wb = XLSX.read(data, {
type: rABS ? 'binary' : 'array'
});
var einAddress = "B3";
var engCodeAddress = "B1";
var goAddress = "B2";
var errMsg = tabName + " tab or required value is missing";
// Worksheet with the necessary info
try {
var ws = wb.Sheets[tabName];
var ein_cell = ws[einAddress];
ein = (ein_cell ? ein_cell.v.toString() : undefined);
var eng_cell = ws[engCodeAddress];
engCode = (eng_cell ? eng_cell.v.toString() : undefined);
var go_cell = ws[goAddress];
goLocator = (go_cell ? go_cell.v.toString() : undefined);
if (ein == undefined || engCode == undefined || goLocator == undefined) {
hasValues = false;
}
excelObject["EngagementCode"] = engCode;
excelObject["GoSystem"] = goLocator;
excelObject["EIN"] = ein;
if (hasValues && isValid) {
uploadFile(fileList[i], userInfo)
.then(resolve);
} else {
noValueErrorHandler(errMsg);
reject();
}
} catch (err) {
hasValues = false;
reject();
}
};
if (rABS) reader.readAsBinaryString(f);
else reader.readAsArrayBuffer(f);
});
}
}

Merge Mutilple pdf blobs into one

Okay so I'm converting html into pdfs, the pdf returned from my backend I convert to a new Blob with type: 'application/pdf', this all works fine. I now want to merge multiple Blobs into one. I'm using the following function to do so.
function ConcatenateBlobs(blobs, type, callback) {
var buffers = [];
var index = 0;
function readAsArrayBuffer() {
if (!blobs[index]) {
return concatenateBuffers();
}
var reader = new FileReader();
reader.onload = function(event) {
buffers.push(event.target.result);
index++;
readAsArrayBuffer();
};
reader.readAsArrayBuffer(blobs[index]);
}
readAsArrayBuffer();
function concatenateBuffers() {
var byteLength = 0;
buffers.forEach(function(buffer) {
byteLength += buffer.byteLength;
});
var tmp = new Uint16Array(byteLength);
var lastOffset = 0;
buffers.forEach(function(buffer) {
// BYTES_PER_ELEMENT == 2 for Uint16Array
var reusableByteLength = buffer.byteLength;
if (reusableByteLength % 2 != 0) {
buffer = buffer.slice(0, reusableByteLength - 1)
}
tmp.set(new Uint16Array(buffer), lastOffset);
lastOffset += reusableByteLength;
});
var blob = new Blob([tmp.buffer], {
type: type
});
callback(blob);
}
}
But for some reason I am only getting the last pdf in the array to show as the result.

I have used Javascript reader.onload = function(e) in apex code and it's not working

I have tried to pass the uploaded files value to apex method but facing some issues in javascript logic.
I have added alert after reader.onload = function(e) but didn't get any alert when I'm hitting this javascript function.
HTML CODE
function SponsorshipLetter() {
var files = document.getElementById('fileUpload');
var appId = getCookie('apex__app');
var fileName = 'Passport';
var reader = new FileReader();
reader.file = files[0];
reader.onload = function(e) {
alert('Hello 1' + document.getElementById('fileUpload').value);
var att = new sforce.SObject("Attachment");
att = fileName;
att.ContentType = this.file.type;
var binary = "";
var bytes = new Uint8Array(e.target.result);
var length = bytes.byteLength;
for (var i = 0; i < length; i++) {
binary += String.fromCharCode(bytes[i]);
}
att.Body = (new sforce.Base64Binary(binary)).toString();
alert('attt');
PAP_Finances.sponsorFileUpload(att.Name, att.Body, att.ContentType, appId,
function(result, event) {
return 'Success';
});
}
reader.readAsDataURL(e.target.files[0]);
}

Categories