I want to create a web app to make simple actions on a csv. For example, the user would upload a csv file then all columns would show up on a form, the user could select some columns to remove them from the file and finally the user could download the modified file.
I have already done something working but there is definitely room for improvement. The most important one is that in my current solution I have to parse the file two times because Papaparse is asynchronous, one time to get the columns and another time to remove columns from the user input.
Is there a way to parse the file only one time and then use the resulting object through the rest of the code ?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>CSV Manipulator</title>
<link rel="stylesheet" href="style.css" />
</head>
<script src="script.js"></script>
<script src="papaparse/papaparse.min.js"></script>
<body>
<div id="csv_columns">
<label for="file">choose csv file</label>
<input id="input-file" autocomplete="off" type="file" id="file" name="file">
<input type="button" value="download CSV" onclick="downloadCSV()">
</div>
<div id="schema_select">
<form action="#">
<label for="schema">Schema</label>
<select name="schema" id="schema" multiple>
</select>
<button id="submit-option">Submit</button>
</form>
<input type="text" , autocomplete="off" name="csv-file-name" id="csv-file-name">
</div>
</body>
</html>
window.onload = function () {
inputElement = document.getElementById("input-file")
inputElement.onchange = function (event) {
var fileList = inputElement.files;
parseDatatoGetSchema(fileList[0])
}
var newCsvFileName = document.getElementById("csv-file-name").value
var submitOption = document.getElementById("submit-option");
submitOption.addEventListener("click", function (event) {
var columnsToRemove = handleSubmit(event)
console.log(columnsToRemove)
parseDataRemoveColumns(inputElement.files[0], columnsToRemove, newCsvFileName)
});
}
function removeColumns(parsedCsv, columnsToRemove) {
newParsedCsv = []
for (i = 0; i < parsedCsv.data.length; i++) {
newObj = {}
for (key in parsedCsv.data[i]) {
if (!(columnsToRemove.includes(key))) {
newObj[key] = parsedCsv.data[i][key]
}
}
newParsedCsv.push(newObj)
}
return newParsedCsv
}
function showCsvSchema(results) {
//Data is usable here
var schemaForm = document.getElementById("schema")
// ajoute le nœud texte au nouveau div créé
for (i = 0; i < Object.keys(results.data[0]).length; i++) {
var opt = document.createElement('option');
opt.value = Object.keys(results.data[0])[i];
opt.innerHTML = Object.keys(results.data[0])[i];
schemaForm.appendChild(opt);
}
}
function handleSubmit(event) {
event.preventDefault();
var schemaSelect = document.getElementById("schema")
columnsToRemove = [...schemaSelect.selectedOptions].map(o => o.value)
return columnsToRemove
}
function parseDatatoGetSchema(url) {
csvData = []
Papa.parse(url, {
header: true,
dynamicTyping: true,
complete: function (results) {
showCsvSchema(results)
}
});
}
function parseDataRemoveColumns(url, columnsToRemove, newCsvFileName) {
csvData = []
Papa.parse(url, {
header: true,
dynamicTyping: true,
complete: function (results) {
newParsedCsv = removeColumns(results, columnsToRemove)
unParsedNewCsv = Papa.unparse(newParsedCsv)
downloadCSV(unParsedNewCsv, newCsvFileName)
}
});
}
function downloadCSV(unparse_csv, newCsvFileName) {
var csvData = new Blob([unparse_csv], { type: 'text/csv;charset=utf-8;' });
var csvURL = null;
if (navigator.msSaveBlob) {
csvURL = navigator.msSaveBlob(csvData, `${newCsvFileName}.csv`);
}
else {
csvURL = window.URL.createObjectURL(csvData);
}
var tempLink = document.createElement('a');
tempLink.href = csvURL;
tempLink.setAttribute('download', `${newCsvFileName}.csv`);
tempLink.click();
location.reload()
}
Related
UPDATED:
I am using RecursiveIteratorIterator to scan the directories to read index.html file.
Now, based on the Pubname and Pubversion, i am trying to read the corresponding index.html file, to get the values of Readability Grade, Readability Score etc. (by storing the values in local storage)
The values are fetched from local storage if i use the html and JS code separately, but after i integrate into php, it is not working.
Code:
<?php
//error_reporting(0);
//Get Pub version
function get_version($path){
$needle = "=";
if(($pos = strpos($path, $needle)) != 0){
$bits = str_split($path, $pos + strlen($needle));
$integer_count = 0;
for($x = 0; $x < strlen($bits[1]); $x++){
if(is_numeric($bits[1][$x])){
$integer_count++;
}else{
break;
}
}
if($integer_count > 0){
$bits = str_split($bits[1], $integer_count);
return $bits[0];
}
}
return -1;
}
$it = new RecursiveDirectoryIterator("C:\Users\Sachin_S2\Desktop\Script");
foreach(new RecursiveIteratorIterator($it,RecursiveIteratorIterator::SELF_FIRST) as $file) {
//IGNORE FILE TYPES
//$filetypes = array("jpg", "png", "pdf", "css", "csv","log","txt");
$htmlfiles = array("html");
$filetype = pathinfo($file, PATHINFO_EXTENSION);
if (in_array(strtolower($filetype), $htmlfiles)) {
// skip dot files while iterating
$it->setFlags(RecursiveDirectoryIterator::SKIP_DOTS);
$files = array($file);
$pathname = $file->getPathname();
print_r($pathname);
$version = get_version($pathname);
if($version > 0){
// use $version to read correct file
include 'html/home.html';
}
echo '*********************************************************************************'.'<br/><br/>';
}
}
html/home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>SEO Metrics</title>
</head>
<body>
<!--Begin script code-->
<form name="myform3">
<!--
<input type="hidden" name="formvar" value="">
<input type="file" name="file" id="file">
<p id="demo"></p><br/><br/>
-->
<div class="form-group">
<label>Readability Grade:</label>
<input type="text" class="form-control" id="grade">
</div>
<div class="form-group">
<label>Readability Score:</label>
<input type="text" class="form-control" id="score">
</div>
<div class="form-group">
<label>Total Word Count:</label>
<input type="text" class="form-control" id="words">
</div>
</form>
<!--END script code-->
<!--Custom JS code-->
<script src="js/home.js"></script>
</body>
</html>
js/home.js
$(document).ready(function() {
document.getElementById('file').onchange = function() {
const file = this.files[0];
const reader = new FileReader();
reader.onload = (event) => {
const file = event.target.result;
const allLines = file.split(/\r\n|\n/);
let arr = allLines;
arr.forEach((kv) => {
if (kv.includes("Flesh-Kincaid Grade Level")) {
var fetch_grade = kv.replace(/<\/?[^>]+(>|$)/g, "");
var formated_grade = fetch_grade.split(":").pop(); //Remove part of the string before ":"
localStorage.setItem("Readability_Grade", formated_grade);
document.getElementById('grade').value = localStorage.getItem("Readability_Grade").replace(/\s/g, ""); //Assign localStorage to text box
localStorage["Readability_Grade"] = grade.value;
//alert(formatedgrade);
}
if (kv.includes("Flesh Reading Ease Score")) {
var fetch_score = kv.replace(/<\/?[^>]+(>|$)/g, "");
var formated_score = fetch_score.split(":").pop();
localStorage.setItem('Readability_Score', formated_score);
document.getElementById('score').value = localStorage.getItem("Readability_Score").replace(/\s/g, "");
//alert(formatedscore);
}
if (kv.includes("Reuse Metrics Score")) {
var metricscore = kv;
//alert(metricscore);
}
if (kv.includes("Total words")) {
var totalwords = kv.replace(/<\/?[^>]+(>|$)/g, "");
var total_words_formated = totalwords.split(":").pop();
localStorage.setItem('Word_Count', total_words_formated);
document.getElementById('words').value = localStorage.getItem("Word_Count").replace(/\s/g, "");
//alert(totalwords);
}
});
};
reader.onerror = (event) => {
alert(event.target.error.name);
};
reader.readAsText(file);
};
});
Output:
On reading this php script, i should be able to read index html (for each file paths - based on pubname and version), and get the values of Readability_Grade and score etc., which i am not able to get.
Firstly get the version number from the string, below is a method to do just that.
function get_version($path){
$needle = "Pub=";
if(($pos = strpos($path, $needle)) != 0){
$bits = str_split($path, $pos + strlen($needle));
$integer_count = 0;
for($x = 0; $x < strlen($bits[1]); $x++){
if(is_numeric($bits[1][$x])){
$integer_count++;
}else{
break;
}
}
if($integer_count > 0){
$bits = str_split($bits[1], $integer_count);
return $bits[0];
}
}
return -1;
}
And then you can use it like this.
foreach ($paths as $path){
$version = get_version($path);
if($version > 0){
// use $version to read correct file
}
}
Thats if I undertoood your question.
Disclaimer: Quickly typed up but should work.
tried to find some useful answer in existing threads but nothing is really matching my issue. I guess there is a quick fix to it, i just cannot see it.
I have a HTML form and want to upload the file to my google drive (works great) and save the text fields to my spreadsheet (does not work at all).
I just cannot find any major difference between the two functions, its frustrating!
Below my code, and here is also the [link to my public script][1].
Form:
<!DOCTYPE html>
<form id="myForm">
<input type="text" name="myName" placeholder="Your name..">
<input type="file" name="myFile">
<input type="submit" value="Upload File"
onclick="this.value='Uploading..';
google.script.run.withSuccessHandler(fileUploaded)
.uploadFiles(this.parentNode);
return false;
google.script.run.withSuccessHandler(fileUploaded)
.doPost(this.parentNode);">
</form>
<div id="output"></div>
<script>
function fileUploaded(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
</script>
<style>
input { display:block; margin: 20px; }
</style>
[1]: https://script.google.com/d/1K9jGl7ALHCZ93rz8GoeV8t7PE_7vgbNZlLJed1h6ZWyuoon11gIbik24/edit?usp=sharing
server.gs:
function doGet(e) {
var html = HtmlService.createTemplateFromFile("form");
html = html.evaluate();
html.setSandboxMode(HtmlService.SandboxMode.IFRAME);
return html;
}
function uploadFiles(form) {
try {
var dropbox = "Customer Shapes";
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var blob = form.myFile;
var file = folder.createFile(blob);
file.setDescription("Uploaded by " + form.myName);
return "File uploaded successfully " + file.getUrl();
} catch (error) {
return error.toString();
}
}
function doPost(form) { // change to doPost(e) if you are recieving POST data
html.setSandboxMode(HtmlService.SandboxMode.EMULATED);
var name = form.myName;
var url="url...";
var message = 'Ram';
var submitSSKey = '...kHI';
var sheet = SpreadsheetApp.openById(submitSSKey).getActiveSheet();
var lastRow = sheet.getLastRow();
var targetRange = sheet.getRange(lastRow+1, 1, 2, 2).setValues([[name,url]]);
}
Thank You for Your kind help!
Martin
If you are going to use google.script.run, then it's pointless to have a function named doPost(). And it's also pointless to have a submit type input tag: type="submit"
If you want to run a withSuccessHandler(fileUploaded) to change the display, you can't have a button inside of the form. It will cause the display to go blank.
And you don't need two google.script.run calls. You need multiple changes and improvements:
form.html
<form id="myForm">
<input type="text" name="myName" placeholder="Your name..">
<input type="file" name="myFile">
</form>
<input type="button" value="Upload File"
onclick="this.value='Uploading..';
var theForm = document.getElementById('myForm');
google.script.run.withSuccessHandler(fileUploaded)
.processFormData(theForm);">
<div id="output"></div>
<script>
function fileUploaded(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
</script>
<style>
input { display:block; margin: 20px; }
</style>
server.gs
function processFormData(form) {
uploadFiles(form.myFile);//Call first function to process the file
var innerArray = [];
var outerArray = [];
innerArray.push(form.myName);
innerArray.push(form.myFile);
outerArray.push(innerArray);//Call second function to write data to SS
writeDataToSS(outerArray);
};
function uploadFiles(theFile) {
try {
var dropbox = "Customer Shapes";
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var blob = theFile;
var file = folder.createFile(blob);
file.setDescription("Uploaded by " + theFile);
return "File uploaded successfully " + file.getUrl();
} catch (error) {
return error.toString();
}
}
function writeDataToSS(values) {
//html.setSandboxMode(HtmlService.SandboxMode.EMULATED);
var url="url...";
var message = 'Ram';
var submitSSKey = '...kHI';
var sheet = SpreadsheetApp.openById(submitSSKey).getActiveSheet();
var lastRow = sheet.getLastRow();
var targetRange = sheet.getRange(lastRow+1, 1, 1, 2).setValues(values);
}
The html file is not a template, it does not have a scriptlet in it. Just use createHtmlOutputFromFile():
function doGet(e) {
var html = HtmlService.createHtmlOutputFromFile("form");
html.setSandboxMode(HtmlService.SandboxMode.IFRAME);
return html;
}
so I am working on a stock market simulator using HTML and JS. I have a api here that gets current stock prices. Here is my HTML http://pastebin.com/ymcGKtin Sorry about pastebin not very good at formatting for SO. But in the function add stock I am trying to push the submitted form stockto the array stocks. However I have run into a problem trying to figure out how to get the submitted form stock and push it to the array. If I could get some pointers on how to do this it would be appricated. To be specific I would like help on getting the attribute stock pushed to the array Stocks. Ideas?
var Market = {};
var Stocks = [];
Market.getQuote = function(symbol, fCallback){
this.symbol = symbol;
this.fCallback = fCallback;
this.DATA_SRC = "http://dev.markitondemand.com/Api/v2/Quote/jsonp";
this.makeRequest();
}
Market.getQuote.handleSuccess = function(jsonResult){
this.fCallback(jsonResult);
}
Market.getQuote.handleError = function(jsonResult){
console.error(jsonResult);
}
Market.makeRequest = function () {
//Abort any open requests
if (this.xhr) { this.xhr.abort(); }
//Start a new request
this.xhr = $.ajax({
data: { symbol: this.symbol },
url: this.DATA_SRC,
dataType: "jsonp",
success: this.handleSuccess,
error: this.handleError,
context: this
});
};
function addStock(){
alert("derp");
// Stocks.push(ele.getAttribute)
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>Stock Market Game PRE ALPHA BETA</title>
</head>
<body>
<form onsubmit = "addStock()">
<input type="text" name="stock" value =""><br><br>
<input type="submit" value="Get Price">
</form>
</body>
</html>
With JQuery you could use find on the form-object (this in the onsubmit-handler):
...
function addStock(form){
var value = $(form).find('input[name="stock"]').val();
alert(value);
Stocks.push(value);
//prevents a submit of the form
return false;
}
</SCRIPT>
<form onsubmit = "return addStock(this);">
<input type="text" name="stock" value =""><br><br>
<input type="submit" value="Get Price">
</form>
...
Changed the addStock() function to use the form element collection method.
function addStock(){
var xForm = document.forms[0];
var xField = xForm.elements[0];
alert("Stock: "+xField.value);
Stocks.push(xField.value);
console.log(Stocks);
}
var Market = {};
var Stocks = [];
Market.getQuote = function(symbol, fCallback) {
this.symbol = symbol;
this.fCallback = fCallback;
this.DATA_SRC = "http://dev.markitondemand.com/Api/v2/Quote/jsonp";
this.makeRequest();
}
Market.getQuote.handleSuccess = function(jsonResult) {
this.fCallback(jsonResult);
}
Market.getQuote.handleError = function(jsonResult) {
console.error(jsonResult);
}
Market.makeRequest = function() {
//Abort any open requests
if (this.xhr) {
this.xhr.abort();
}
//Start a new request
this.xhr = $.ajax({
data: {
symbol: this.symbol
},
url: this.DATA_SRC,
dataType: "jsonp",
success: this.handleSuccess,
error: this.handleError,
context: this
});
};
function addStock() {
var xForm = document.forms[0];
var xField = xForm.elements[0];
alert("Stock: " + xField.value);
Stocks.push(xField.value);
console.log(Stocks);
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Stock Market Game PRE ALPHA BETA</title>
</head>
<body>
<form onsubmit="addStock()">
<input type="text" name="stock" value="">
<br>
<br>
<input type="submit" value="Get Price">
</form>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>
</body>
</html>
I am trying to print the text multiple files in html. I succeeded in printing the single file. But I am unable to print the text output of a multiple files. Can you please help me in correcting the code?`
<!DOCTYPE html>
<html>
<body>
<h1> Testing programs </h1>
<input type="file" id="fileinput" multiple />
<pre id="file-content"></pre>
<h3>Contents of the file:</h3>
<script type="text/javascript">
function readMultipleFiles(evt) {
//Retrieve all the files from the FileList object
var files = evt.target.files;
if (!files) {
for (var i=0, f; f=files[i]; i++) {
var r = new FileReader();
r.onload = (function(f) {
return function(e) {
var contents = e.target.result;
displayContents(contents);
};
});
r.readAsText(f);
}
} else {
alert("Failed to load files");
}
function displayContents(contents) {
var element = document.getElementById('file-content');
element.innerHTML = contents;
}
document.getElementById('fileinput').addEventListener('change', readMultipleFiles, false)
</script>
</body>
</html>`
There is no need to use closure in provided snippet. As suggested by gurvinder, use innerHTML +=
if condition should be like if (files) as it will be true if length of files is greater than 0
Try this:
function readMultipleFiles(evt) {
var files = evt.target.files;
if (files) {
for (var i = 0; i < files.length; i++) {
var r = new FileReader();
r.onload = function(e) {
var contents = e.target.result;
displayContents(contents);
};
r.readAsText(files[i]);
}
} else {
alert("Failed to load files");
}
}
function displayContents(contents) {
var element = document.getElementById('file-content');
element.innerHTML += contents;
}
document.getElementById('fileinput').addEventListener('change', readMultipleFiles, false);
<h1> Testing programs </h1>
<input type="file" id="fileinput" multiple />
<pre id="file-content"></pre>
<h3>Contents of the file:</h3>
Also refer this fiddle : https://jsfiddle.net/rayon_1990/2cwr4c00/
just replace the displayContents method as
function displayContents(contents) {
var element = document.getElementById('file-content');
element.innerHTML += contents; //observe + before =
}
since it needs to append the files rather than replace the last one
I have following code for checking whether there is duplicate in an array. The code works fine. But it uses a new array named newUniqueArray. Is there a better code for this purpose without using a new array? Is there any optimization possible on this code?
Note: I have used inArray and in keywords from jQuery
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.4.1.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$('#btnSave').click(function (e) {
var reportRecipients = "A, a , b,";
reportRecipients = reportRecipients.toLowerCase();
checkDuplicate(reportRecipients);
});
function checkDuplicate(reportRecipients) {
if (reportRecipients.length > 1) {
var recipientsArray = reportRecipients.split(',');
var newUniqueArray = [];
for (a in recipientsArray) {
var email = $.trim(recipientsArray[a]);
if ($.inArray(email, newUniqueArray) == -1) {
newUniqueArray.push(email);
}
}
if (newUniqueArray.length < recipientsArray.length) {
alert('Duplicate Exists');
}
return false;
}
}
});
</script>
</head>
<body>
<input name="txtName" type="text" id="txtName" />
<input type="submit" name="btnSave" value="Save" id="btnSave" />
</body>
</html>
If you just want to test on string arrays, you can use a JavaScript object's property to test. It used a hash-table to look up properties, which is faster than array iteration.
example: http://jsfiddle.net/jmDEZ/8/
function checkDuplicate(reportRecipients) {
var recipientsArray = reportRecipients.split(','),
textHash = {};
for(var i=0; i<recipientsArray.length;i++){
var key = $.trim(recipientsArray[i].toLowerCase());
console.log("lower:" + key);
if(textHash[key]){
alert("duplicated:" + key);
return true;
}else{
textHash[key] = true;
}
}
alert("no duplicate");
return false;
}
I can't see any reason to use jQuery for this purpose:
checkDuplicate = function (reportRecipients) {
if (reportRecipients.length > 1) {
var recipientsArray = reportRecipients.split(',');
for (a in recipientsArray) {
if(reportRecipients.indexOf(a) != reportRecipients.lastIndexOf(a)){
return true;
}
}
}
return false;
}
$('#btnSave').click(function (e) {
var reportRecipients = "A, a , b,";
reportRecipients = reportRecipients.toLowerCase();
if(checkDuplicate(reportRecipients)) alert('Duplicate Exists');
});