I want to create a single web page using html and javascript in which user can upload an excel(.xlsx, .xls) file as an input.
After uploading excel sheet the web page should use the javascript logic.
It could read that excel sheet and make changes using some js logic.
After writing into excel, web page should have a download button to download the new excel sheet.
Do I need to use Node js to do that or is it possible to use some cdn script tags of excel-js library, which is not working for me(I dont know why)
<script src="https://cdnjs.cloudflare.com/ajax/libs/exceljs/4.2.1/exceljs.min.js" integrity="sha512-DPjFYmSXYGB7/5k/Z4h5iw1i29Vl//jj3I7v79DRy+T0o4KssDku6Hf7ImlIV87KmNIh+euT5H0LJhQmTnbC/A==" crossorigin="anonymous"></script>
Whenever I try to use some function of this library like , it throws me error
function excelChange (event) {
var input = event.target.files[0]
const workbook = createAndFillWorkbook();
const sheet = workbook.xlsx.writeFile(input);
console.log(sheet)}
What should be my approach to achieve this goal ?
CSV Excel files are comma separated like this
name, age,
john, 33,
bob, 55,
So you could just read it as a string and make an array from it. Then render the array into a table. Do the reverse to make a CSV Excel file.
const excelString = `
name, age,
john, 33,
bob, 55,
`;
function parse(string){
return string.trim().split("\n").map(row => row.trim().split(",").map(val => val.trim()).filter(str => str));
}
const parsed = parse(excelString);
const [head, ...body] = parsed;
function addElement(tag, data, editable){
const elm = document.createElement(tag);
if(data) elm.textContent = data;
if(editable) elm.contentEditable = true;
return elm;
}
document.querySelector("table").appendChild(
addElement("tr")
);
head.map(header => {
document.querySelector("tr:last-child").appendChild(
addElement("th", header, true)
);
});
body.map(row => {
document.querySelector("table").appendChild(addElement("tr"));
row.map(item => {
document.querySelector("tr:last-child").appendChild(
addElement("td", item, true)
);
});
});
function table2excel(){
return Array.from(document.querySelectorAll("tr")).map(row => {
return Array.from(row.querySelectorAll("th, td"))
.map(elm => elm.textContent);
}).map(row => row.join(",")).join(",\n").concat(",")
}
const newExcel = table2excel();
console.log(newExcel)
document.querySelector("button").addEventListener("click", () => console.log(table2excel()))
<table />
<button>Log table</button>
Related
so I'm doing a school project where I'm trying to fetch data from my Azure blob-storage and then displaying it on a website which is creating in ReactJS. I've managed to fetch the pictures from my storage and they render fine, but when I try to render the "createdOn prop" nothing is being shown.
I just wanna add that I'm fairly new to javascript so my code might look like garbage.
The BodyPresenter function is the one that connects to my blob storage and then retrieves the data. It works without a problem for the "blobImages" but won't work for the "blobDateTime"
function BodyPresenter() {
const [blobImages, setBlobImages] = useState([]);
const [blobDateTime, setBlobDateTime] = useState([]);
const account = "ktodb";
const containerName = "images";
useEffect(() => {
async function blobStorage() {
const blobServiceClient = new BlobServiceClient(api_client.get_blob_account(account));
const containerClient = blobServiceClient.getContainerClient(containerName);
let blobs = containerClient.listBlobsFlat();
let newArrayForImages = [];
let newArrayforDates = [];
for await (const blob of blobs) {
// console.log(`${blob.name}`); //`Blob ${i++}:
newArrayForImages.push(blob.name);
newArrayforDates.push(blob.properties.createdOn)
}
setBlobImages(newArrayForImages);
setBlobDateTime(newArrayforDates);
}
return blobStorage;
}, [blobImages])
console.log(blobDateTime)
As you can see I console.log() the blobDateTime at the bottom and it gives me the data I want in the console, aka the creation data of all my images:
image of console
Then I try to render the data in a view file and I guess the problem lies here, but I'm sure what the problem is and how to fix it, to remind you I'm a new to javascript. The images are being rendered but not the DateTime
function BodyView( {blobImages, blobDateTime} ) {
console.log(blobDateTime)
return (
<div>
{blobImages.map( (blobImages, blobDateTime) => (
<div>
<div className="images">
<img
key={blobImages.id}
src={api_client.get_image_url(blobImages)}
alt=""
/>
</div>
<div>{blobDateTime}</div>
</div>
))}
</div>
)
}
I'm generating PDF by using https://pdfgeneratorapi.com/.
Now I can show data one by one using this code.Can any one give me suggestion how can show all data with loop or any other way?
This below photos showing my template from pdfgenerator .
This is the code I'm using to generate PDF
let communicationWay1=[
{0:"dim"},
{1:"kal"}
];
let cstomerExpence1=[
{0:"dim"},
{1:"kal"}
];
let title="test";
let names="test";
let phone="test";
let email="test";
let maritalStatus="test";
let city="test";
let other="test";
const result = await wixData.query(collection)
.eq('main_user_email', $w('#mainE').text)
.find()
.then( (results) => {
if (results.totalCount>0) {
count=1;
// title=results.items[1].title;
names=results.items[0].names;
email=results.items[0].emial;
phone=results.items[0].phone;
maritalStatus=results.items[0].maritalStatus;
city=results.items[0].city;
other=results.items[0].cousterExpenses_other;
title=results.items[0].title;
communicationWay=results.items[0].communicationWay;
cstomerExpence=results.items[0].cstomerExpence;
}
if (results.totalCount>1) {
names1=results.items[1].names;
email1=results.items[1].emial;
phone1=results.items[1].phone;
maritalStatus1=results.items[1].maritalStatus;
city1=results.items[1].city;
other1=results.items[1].cousterExpenses_other;
title1=results.items[1].title;
communicationWay1=results.items[1].communicationWay;
cstomerExpence1=results.items[1].cstomerExpence;
}
} )
.catch( (err) => {
console.log(err);
} );
// Add your code for this event here:
const pdfUrl = await getPdfUrl
({title,names,email,phone,city,maritalStatus,other,communicationWay,cstomerExpence,title1,
names1,email1,phone1,city1,maritalStatus1,other1,communicationWay1,cstomerExpence1
});
if (count===0) { $w("#text21").show();}
else{ $w("#downloadButton").link=wixLocation.to(pdfUrl);}
BELOW CODE IS BACKEND CODE/JSW CODE.
Also I want to open pdf in new tab. I know "_blank" method can be used to open a new tab.But I'm not sure how to add it with the url
import PDFGeneratorAPI from 'pdf-generator-api'
const apiKey = 'MYKEY';
const apiSecret = 'MYAPISECRET';
const baseUrl = 'https://us1.pdfgeneratorapi.com/api/v3/';
const workspace = "HELLO#gmail.com";
const templateID = "MYTEMPLATEID";
let Client = new PDFGeneratorAPI(apiKey, apiSecret)
Client.setBaseUrl(baseUrl)
Client.setWorkspace(workspace)
export async function getPdfUrl(data) {
const {response} = await Client.output(templateID, data, undefined, undefined, {output: 'url'})
return response
}
Just put it in a while loop with a boolean condition.
You can create a variable, for example allShowed, and set its value to False. After that, create another variable, for example numberOfDataToShow, and set it as the number of elements you want to display. Then create a counter, countShowed, initialized with 0 as its value.
Now create a while loop: while allShowed value is False, you loop (and add data).
Everytime a piece of your data is showed, you increment the value of countShowed (and set it to go on adding/showing data). When countShowed will have the exact same value of numberOfDataToShow, set allShowed to True. The loop will interrupt and all your data will be showed.
You would need to use the Container or Table component in PDF Generator API to iterate over a list of items. As #JustCallMeA said you need to send an array of items. PDF Generator API now has an official Wix Velo (previously Corvid) tutorial with a demo page: https://support.pdfgeneratorapi.com/en/article/how-to-integrate-with-wix-velo-13s8135
I have a Google spreadsheet with links to questionnaires. I wanted to know how to get the questions from each of the questionnaires.
I guess I have to do: at best, use the script editor and iterate on the lines, and at worst, do webscraping.
const puppeteer = require('puppeteer');
function appendString() {
var range = SpreadsheetApp.getActiveSheet().getActiveRange();
var numRows = range.getNumRows();
var numCols = 0;
for (var i = 1; i <= numRows; i++) {
for (var j = 1; j <= numCols; j++) {
var currentValue = range.getCell(i,j).getValue();
await page.goto(currentValue);
const pollFrame = page.frames().find() # From there I have some difficulties
}
}
}
But I get the following error:
SyntaxError: await is only valid in async function (ligne 10, fichier "Code.gs")
Not to mention the async problem or the buttonthat I still have to click, the selection looks like this:
<div class="freebirdFormviewerViewItemsItemItemTitle exportItemTitle freebirdCustomFont" id="i1" role="heading" aria-level="3" aria-describedby="i.desc.310938276">How often did you fly before the Covid-19 epidemic? </div>
But the IDs don't follow a logical numerical order, so I don't know how to extract them automatically.
Then I don't know how to do it. I wonder if it's simpler because they're products from the same supplier.
Here is the equivalent in csv format:
https://docs.google.com/forms/d/e/1FAIpQLSfzocEm6IEDKVzVGOlg8ijysWZyAvQur0NheJb_I_xozgKusA/viewform?usp=sf_link
https://docs.google.com/forms/d/e/1FAIpQLScrm0ZTrvlONf5MX37N93H_FajNzfbNy9ZtitX-Vq9PPuLPHA/viewform?usp=sf_link
https://docs.google.com/forms/d/e/1FAIpQLSeolFSh3OyS_XpX1lRIJP-8CH8WG0X0hL98SM9d85LqC22Bow/viewform?usp=sf_link
Update
So I tried the anwer kindly posted by Neven Subotic's:
// this array will store forms and their questions
let formAndQuestions = [];
let formIds = ["https://docs.google.com/forms/d/e/1FAIpQLSfzocEm6IEDKVzVGOlg8ijysWZyAvQur0NheJb_I_xozgKusA/viewform?usp=sf_link",
"https://docs.google.com/forms/d/e/1FAIpQLScrm0ZTrvlONf5MX37N93H_FajNzfbNy9ZtitX-Vq9PPuLPHA/viewform?usp=sf_link",
"https://docs.google.com/forms/d/e/1FAIpQLSeolFSh3OyS_XpX1lRIJP-8CH8WG0X0hL98SM9d85LqC22Bow/viewform?usp=sf_link"]
formIds.forEach( formId => {
const form = FormApp.openById( formId );
// lets get the name
const formName = form.getTitle();
// first we get all items
const allItemsInThisForm = form.getItems();
// then we get filter out anything that is not a questions
const allQuestionsInThisForm = allItemsInThisForm.filter( item => {
return isThisItemAQuestion( item )
});
// now we store them in our object
formAndQuestions.push( {
formId: formId,
formName: formName,
questions: allQuestionsInThisForm
})
});
// this function is used to only get the itemTypes you want
// see reference for more information
function isThisItemAQuestion( item ){
const itemType = item.getType();
const validQuestionItemTypes = [ FormApp.ItemType.TEXT, "add others here" ]
let isValid = false;
validQuestionItemsTypes.forEach( validItemType => {
if( itemType == validItemType ) {
isValid = true;
}
});
return isValid
}
Unfortunately I obtain the following error message with the following details Exception: No item with the given ID could be found, or you do not have permission to access it. (line 9, "const form = FormApp.openById( formId );"). I don't understand. As you can see in the gif, I can open these links, so I should have the permission to access them isn't it?
I also tried Ruben's ideas with:
// this array will store forms and their questions
let formAndQuestions = [];
let formIds = ["https://docs.google.com/forms/d/e/1FAIpQLSfzocEm6IEDKVzVGOlg8ijysWZyAvQur0NheJb_I_xozgKusA/viewform?usp=sf_link"]//,
//"https://docs.google.com/forms/d/e/1FAIpQLScrm0ZTrvlONf5MX37N93H_FajNzfbNy9ZtitX-Vq9PPuLPHA/viewform?usp=sf_link",
//"https://docs.google.com/forms/d/e/1FAIpQLSeolFSh3OyS_XpX1lRIJP-8CH8WG0X0hL98SM9d85LqC22Bow/viewform?usp=sf_link"]
function scrapeForms(){
formIds.forEach( formId => {
// The code below logs the HTML code of the Google home page.
var response = UrlFetchApp.fetch(formId);
results = response.getElementsByClassName("freebirdFormviewerViewItemsItemItemTitleContainer");
Logger.log(results.getContentText())
});
}
But got back:
TypeError: response.getElementsByClassName is not a function (ligne 13, fichier "Code")
According to What is this Javascript "require"? require is not part of the standard JavaScript an AFAIK it's not supported by Google Apps Script.
By the other hand, the error message can't be easily solved as Google Apps Script Chrome V8 engine doesn't support async functions. Related Is google apps script synchronous?
If you will be using Google Apps Script, and you are the form owner or a form editor, instead of trying to web scraping a Google Form use the Forms Service of Google Apps Script. For this you will need the form ../edit URLs instead of the ../viewform URLs. On the official docs there is a quickstart that might help you https://developers.google.com/apps-script/quickstart/forms.
You could use openByUrl to "open" a form. It will not be actually opened in your web browser, it will be opened on the server side. Then you could use getItems to get all the questions, sections, images, videos, etc.
If you aren't the form owner or a form editor then you should use UrlFetchApp service and somehow parse the web page source code of each form based on the position of the questions. Related question: Google Sheets: How to import the following data?
Also, if the form has several sections you should do a post request to emulate clicking on the next button in order to get the second and following sections. There are more "also if the form has..." but I will stop here as the main part of question was already answered, I think.
You first want to get all the forms, so place those in an array:
const formIds = ["someId", "anotherId", "andSoOn"]
Then, lets use the FormApp to get the form and all items. Items can be of different types, see documentation.
// this array will store forms and their questions
let formAndQuestions = [];
formIds.forEach( formId => {
const form = FormApp.openById( formId );
// lets get the name
const formName = form.getTitle();
// first we get all items
const allItemsInThisForm = form.getItems();
// then we get filter out anything that is not a questions
const allQuestionsInThisForm = allItemsInThisForm.filter( item => {
return isThisItemAQuestion( item )
});
// now we store them in our object
formAndQuestions.push( {
formId: formId,
formName: formName,
questions: allQuestionsInThisForm
}
});
// this function is used to only get the itemTypes you want
// see reference for more information
function isThisItemAQuestion( item ){
const itemType = item.getType();
const validQuestionItemTypes = [ FormApp.ItemType.TEXT, "add others here" ]
let isValid = false;
validQuestionItemsTypes.forEach( validItemType => {
if( itemType == validItemType ) {
isValid = true;
}
});
return isValid
}
Then you can initially log out the results and see what it looks like:
Logger.log( formAndQuestions )
Item Types
I'm trying to obtain the File value within this stack trace
however im getting an undefined when calling it like
console.log(e.target.File);
or
console.log(e.target)
How would i access the file value ?
handleUpload = (e) => {
const data = new FormData()
console.log(e.target);
// data.append('file', e.target.files[0])
// data.append('name', 'some value user types')
// data.append('description', 'some value user types')
// Axios.post('/images/upload', data).then((response) => {
// console.log(response);
debugger;
// this.setState({
// imageUrl: response.data.fileUrl
// })
render(){
return(
.......
<ImageUploader
withIcon={true}
withPreview={true}
buttonText='Upload an image'
imgExtension={['.jpg', '.gif', '.png', '.gif']}
onChange={this.handleUpload}
maxFileSize={5242880}
/>
}
It appears that you are using a React ImageUploader component that is already handling extracting your files from the event. The e in your handleUpload isn't an event rather than the extracted file list. You should work with this file list directly.
You can look into the ImageUploader source to see how it is handling it if you would like to better understand, but accessing the files through e[0] is fine (you may want to rename e to something like files for clarity though).
We don't know the implementation of ImageUploader but from the screenshot it seems that it calls the onChange method with an array of files. So you can access them like that:
handleImagesChange = images => {
const firstImage = images[0];
console.log(firstImage.name);
this.setState({ images });
}
handleSubmit = () => {
Axios.post('some/url', this.state.images)
.then(console.log)
}
I'm working on a CSV uploader that uses PapaParse as it's CSV parser. For my CSV I would like my first column to act as my header for the parsed data as opposed to the first row. In order to get the expected outcome, I've been having to manually transpose the CSV in the editor before uploading.
The reason for this is that my users find it much easier to edit the CSV when the headers are in the first column and not the first row. Is there a way I can do this in PapaParse (or even JavaScript outside of PapaParse)?
if (file != null) {
Papa.parse(file, {
header: true,
complete: function (results, file) {
console.log("Parsing complete: ", results, file);
}
});
}
I would suggest to parse the array with PapaParse and then perform transpose over the result with JS.
Using this method: https://stackoverflow.com/a/4492703/1625793
So it would look like that transpose(result.data)
-- Update --
const transposed = transpose(result.data)
const headers = transposed.shift();
const res = transposed.map(row => row.reduce((acc, col, ind) => {acc[headers[ind]] = col; return acc}, {}))