This is a follow-up to a previous post (solved). In the previous post we loaded a delimited text file then took action on the contents of the file. But what we did was in one smooth progression of events. In my actual implementation, events will occur separately. First, a tab delimited text file will be loaded, using the FileReader API, and displayed on the page. Much later a function will need to retrieve the loaded content and do stuff with it. I thought I would have no difficulty separating the tasks, but I was wrong. I don't know what I'm doing wrong or if I'm going about it the wrong way. I'd appreciate some input.
Note: I don't necessarily have to use the information directly from the pre-tag "fileDisplayArea". I just thought that would work and be easy. I could use the string stored in memory, if that is better. The string should never be more than 6 or 7 Mb.
What do I need to do to, so at a later time I can use the string loaded and placed in "fileDisplayArea"?
Thanks in advance,
Andrew
var fileInput = document.getElementById('fileInput');
fileInput.addEventListener('change', function (e) {
var file = fileInput.files[0];
var textType = /text.*/;
if (file.type.match(textType)) {
var reader = new FileReader();
reader.onload = function (e) {
// Entire file
fileDisplayArea.innerText = reader.result;
}
reader.readAsText(file);
} else {
fileDisplayArea.innerText = "File not supported!"
}
});
// doIt functionality
document.getElementById("doIt").addEventListener("click", function () {
var myTemp = document.getElementById("fileDisplayArea");
console.log(myTemp);
// trying to retreive original reader.result contents so I can do stuff with it
// i thought it would be as simple as using getElementByID, but i'm obviously wrong
}, false);
<br />
Step 1:<br />
Select a text file:
<input type="file" id="fileInput">
<hr />
Step 2:<br />
Retreive the contents previously loaded. (Normally 'doIt' would be called from another function, not a button.)
<button id="doIt">doIt</button>
<hr />
<pre id="fileDisplayArea"></pre>
Related
So I am trying to do some client side validation on an app I am working on, and I want to be able to check the number of columns in a CSV that the user uploads. The CSVs could potentially be very large (up to 30 thousand rows) so I'm worried that my current method, which reads the entire file, is not the best way to do it.
This is what I have right now.
// Function to validate the File Upload
$(document).ready(function() {
$("#csv").change(function () {
console.log("Read CSV Function Triggered");
let theFile = document.getElementById("csv").files[0];
let reader = new FileReader();
reader.addEventListener('load', readFile);
reader.readAsText(theFile);
function readFile(event) {
let csvText = event.target.result;
let firstLine = csvText.split('\n').shift(); // First Line
$("#result").html(firstLine);
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="file" id="csv" />
<br>
<span id="result">0</span>
In the example I just make the first line display on the page, but in the app I have a parser library that I couldn't include in this example which converts the first line to an array and then I get the length of the array. So like I said before, this works, but I am worried that when large CSVs are uploaded it may affect browser performance.
Any suggestions?
First of all Sorry for the length heading. Currently working on custom file input where with my current code i can able to upload the only jpeg file if the user uploading some other format it will show error message you have to upload only jpg
when the user click the next button jquery should validate the file input and it should say in the message you have missed one field currently I gave required for the input field still it was not validting the field. I am struggling lot not getting anything in my mind help me.
Here is the jquery code
function showImage() {
var files = !! this.files ? this.files : [];
var regex = /^([a-zA-Z0-9\s_\\.\-:])+(.jpg|.jpeg)$/;
// No file selected, or no FileReader support
if (!files.length || !window.FileReader) return;
// If the file is a JPEG image
if (regex.test(files[0].type)) {
// Create an instance of FileReader
var reader = new FileReader();
// Declare the onload callback before reading the file
reader.onload = function () {
// Set image data as background of div
$preview.css("background-image", "url(" + this.result + ")");
// Empty the error message
$errorLabel.text('');
// Disable file selection
$fileInput.prop('disabled', true);
// Show the buttons
$deleteBtn.show();
$sendBtn.show();
$imagecontainer.hide();
};
// Read the local file
reader.readAsDataURL(files[0]);
} else {
// Add an error message
$errorLabel.text('Please upload only jpeg');
$errorLabel.css("color","red");
$fileInput.addClass('errRed');
}
}
Here is the fiddle link
Kindly please guide me
Thanks in advance
html code
<input name="Select File upload" accept="image/jpeg" required class="upload" id="upload" type="file" />
Now I gave new property call accept input file user can upload only jpeg image this was happening correctly but my validation count was not reduced with this :(
Your regex won't validate against the type attribute, as it returns the MIME type of the file, and your regex is looking at the file extension. Use the name attribute instead if you want to keep using that regex.
In other words, try changing
regex.test(files[0].type)
to
regex.test(files[0].name)
Finally after long hours i found the answer for this issue :) I need to put one single line that was the most funniest part here.
this is the line which was so much time i need to put this line in the condition :) $(".basicForm").validate().element("#upload");
if (regex.test(files[0].type)) {
// Create an instance of FileReader
var reader = new FileReader();
// Declare the onload callback before reading the file
reader.onload = function () {
// Set image data as background of div
$preview.css("background-image", "url(" + this.result + ")");
// Empty the error message
$errorLabel.text('');
//$('.choose_file').removeClass('errRed');
$(".basicForm").validate().element("#upload");
$('#imageUploadForm').removeClass('errRed');
// validate();
// Disable file selection
$fileInput.prop('disabled', true);
// Show the buttons
$deleteBtn.show();
$sendBtn.show();
$imagecontainer.hide();
};
// Read the local file
reader.readAsDataURL(files[0]);
} else {
//alert("sorry not an jpeg file");
// Add an error message
$(".basicForm").validate().element(".upload");
$fileInput.val('');
$errorLabel.text('Please upload only jpeg');
$errorLabel.css("color","red");
$fileInput.addClass('errRed');
//$(event).preventDefault();
var control = $("#files");
control.replaceWith( control = control.clone( true ) );
$(".btn-next").trigger('click');
}
I am trying to read a local file and have each line as an index in an array using JavaScript. I have been searching for the past 20 minutes and either I'm stupid or there really isn't an answer that pertains to my problem (...but it's probably the former :P). I am really new to JavaScript so if you have an answer could you please comment the code just to I know what's going on?
Also, from the searching I've done on the internet some people said JavaScript can't read local file for security reasons so if that is correct is there another language I can use? I'm a bit familiar with PHP if that is an option, which I doubt it is.
EDIT
As per thg435's question, I'll explain what I am trying to accomplish.
My project is to analyze a BUNCH of water quality data that has been collected by the Ontario gov't (which I've done) and display it in some way. I have chosen to display it on a webpage using the Google Maps API. I currently have a file of chemicals that were found. Each line is a different chemical. I would like to read the file in an array then create an option menu displaying the chemicals in the array.
Also, the local file I would like to read will the be the same name and location all the time. I have seen people have boxes where the user clicks and chooses their file or to drag and drop but that's not what I'm looking for.
I don't think I explained this properly. I have a file in the same directory as my HTML and JavaScript files that contains words. Example:
Line 1: "Iron"
Line 2: "Aluminum"
Line 3: "Steel"
etc...
I would like to read the file and parse each line into a different index in an array. I don't want the user to be able to choose which file to read using the <input ... /> thing.
You're going to want to take a look at the FileReader API. This should allow you to read the text of a local file via readAsText(). This won't work in every browser but should work in all modern browser. You can see which browsers support it here.
Example:
<input id="file" type="file" />
var filesInput = document.getElementById("file");
filesInput.addEventListener("change", function (event) {
var files = event.target.files;
var file = files[0];
var reader = new FileReader();
reader.addEventListener("load", function (event) {
var textFile = event.target;
alert(textFile.result);
});
reader.readAsText(file);
});
It's not possible to invoke the FileReader API without user interaction. Consequently, your user would have to select whatever file to load in order for it to be read in pure JS. Since I'm assuming this will be up on a server, why not just put the list of chemicals also up on the server and GET the JSON encoded array of the results. Then you can decode them with Javascript.
You can access local files in 2 ways that I know of. The first way is making the user drag-and-drop the files onto the page, and using an <input type="file"> tag.
For the former, you would need to do the following:
addEventListener('dragover', function(e){e.preventDefault();});
addEventListener('drop', function(e) {
eventHandler.call(e.dataTransfer||e.clipboardData);
e.preventDefault();
});
For the latter, you'd need to add an event listener for the change event on the input:
document.getElementById('upload').addEventListener('change', eventHandler)
And for both, you'd need to have this as a basic callback function:
function eventHandler() {
var file = this.files[0]; //get the files
var reader = new FileReader(); //initiate reader
reader.onloadend = callbackFn; //set event handler
reader.readAsText(file); //initiate reading of files
if (this.id) { //only run if this is the input
var id = this.id;
this.outerHTML = this.outerHTML; //this resets the input
document.getElementById(id).addEventListener('change', eventHandler); //reattach event handler
}
function callbackFn(e) {
document.getElementById('output').value = e.target.result; //output it to a textarea
}
}
Here is a demo where the text contents (that what you see when opening it in notepad) of any file you drop in it, or any file you select from the input, is put in the textarea.
For more information, see https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications.
How to remove one specific selected file from input file control?
I have an input file control with the option to select multiple files; however, I want to validate a file and if it has an wrong extension then I should remove that file from the file control itself, is it possible?
I tried as below
<input type="file" name="fileToUpload" id="fileToUpload" multiple/>
<script> $("#fileToUpload")[0].files[0] </script>
Below is the screenshot of the object but I am not able to modify it
As other people pointed out, FileList is read only. You can get around this by pushing those files into a separate Array though. You can then do whatever you want with that curated list of files. If uploading them to a server is the goal, you can use the FileReader API.
Below is a round about way of completely avoiding needing to modify the FileList.
Steps:
Add normal file input change event listener
Loop through each file from change event, filter for desired validation
Push valid files into separate array
Use FileReader API to read files locally
Submit valid, processed files to server
Event handler and basic file loop code:
var validatedFiles = [];
$("#fileToUpload").on("change", function (event) {
var files = event.originalEvent.target.files;
files.forEach(function (file) {
if (file.name.matches(/something.txt/)) {
validatedFiles.push(file); // Simplest case
} else {
/* do something else */
}
});
});
Below is a more complicated version of the file loop that shows how you can use the FileReader API to load the file into the browser and optionally submit it to a server as a Base64 encoded blob.
files.forEach(function (file) {
if (file.name.matches(/something.txt/)) { // You could also do more complicated validation after processing the file client side
var reader = new FileReader();
// Setup listener
reader.onload = (function (processedFile) {
return function (e) {
var fileData = { name : processedFile.name, fileData : e.target.result };
// Submit individual file to server
$.post("/your/url/here", fileData);
// or add to list to submit as group later
validatedFiles.push(fileData);
};
})(file);
// Process file
reader.readAsDataURL(file);
} else {
/* still do something else */
}
});
A note of caution about using FileReader API. Base64 encoding a file will increase its size by around 30%. If that isn't acceptable you will need to try something else.
I know this is an old post but I have spent ages trying to work around this one so I'll post my solution. There is a way to update the fileList of an fileField element with another fileList - which can be done with DataTransfer:
let updateFileList = function (fileField, index) {
let fileBuffer = Array.from(fileField.files);
fileBuffer.splice(index, 1);
/** Code from: https://stackoverflow.com/a/47172409/8145428 */
const dT = new ClipboardEvent('').clipboardData || // Firefox < 62 workaround exploiting https://bugzilla.mozilla.org/show_bug.cgi?id=1422655
new DataTransfer(); // specs compliant (as of March 2018 only Chrome)
for (let file of fileBuffer) { dT.items.add(file); }
fileField.files = dT.files;
}
The above function takes the fileField as a DOM Object and the index of the file in the fileField's fileList to be removed and updates the passed fileField accordingly.
Hope this saves somebody else some time!
How to set File objects and length property at FileList object where the files are also reflected at FormData object?
I thought that I should add my comment here as well here (I've answered here: JavaScript delete File from FileList to be uploaded)
I found a workaround. This will not require AJAX for the request at all and the form can be sent to the server. Basically you could create an hidden or text input and set it's value attribute to the base64 string created after processing the file selected.
<input type=hidden value=${base64string} />
You will probably consider the idea to create multiple input file instead of input text or hidden. This will not work as we can't assign a value to it.
This method will include the input file in the data sent to the database and to ignore the input file you could:
in the back-end don't consider the field;
you can set the disabled attribute to the input file before serialising the form;
remove the DOM element before sending data.
When you want to delete a file just get the index of the element and remove the input element (text or hidden) from the DOM.
Requirements:
You need to write the logic to convert files in base64 and store all files inside an array whenever the input file trigger the change event.
Pros:
This will basically give you a lot of control and you can filter, comparing files, check for file size, MIME type, and so on..
Based on #liamthorne4 answer, here is a working solution for upload, list and delete element from list, tested on Firefox and Chrome:
HTML:
<button onclick="uploadFile(event)">Upload files</button>
<div id="listfiles" class="view_list"></div>
<input class="hidden" type="file" id="input_file_id" onchange="fileList(event)" name="files[]" multiple>
JS:
function uploadFile(evt) {
evt.preventDefault();
$('#input_file_id').click();
}
function fileList(e) {
var files = $('#input_file_id').prop("files");
var names = $.map(files, function(val) { return val.name; });
for (n in names) {
$("#listfiles").append("<div id=preload_"+n+" title='"+names[n]+"'><p>"+names[n]+"</p><a onclick=deleteFile("+n+")>Delete</a></div>");
}
}
function deleteFile(index) {
filelistall = $('#input_file_id').prop("files");
var fileBuffer=[];
Array.prototype.push.apply( fileBuffer, filelistall );
fileBuffer.splice(index, 1);
const dT = new ClipboardEvent('').clipboardData || new DataTransfer();
for (let file of fileBuffer) { dT.items.add(file); }
filelistall = $('#input_file_id').prop("files",dT.files);
$("#preload_"+index).remove()
}
html
<input id="fileInput" name="fileInput" type="file" />
<input onclick="clearFileInput()" type="button" value="Clear" />
javascript
function clearFileInput(){
var oldInput = document.getElementById("fileInput");
var newInput = document.createElement("input");
newInput.type = "file";
newInput.id = oldInput.id;
newInput.name = oldInput.name;
newInput.className = oldInput.className;
newInput.style.cssText = oldInput.style.cssText;
// copy any other relevant attributes
oldInput.parentNode.replaceChild(newInput, oldInput);
}
UPDATE:
For testing purposes, I used
<input type="text" onClick="doProcess(http://www.abc.com/chart.png)" />
That didn't work (used alert to test if url was being passed. The alert box did show up with the url, but decoding failed). In a sense, I answered a part of my question myself. Any ideas on how to read an image file through javascript?tt
Just found that this is HTML 5 related code. Also I figured since I'm passing a url instead of list of files, I'll need to remove the for() loop from the doProcess() function which would be
function doProcess(f)
{
var o=[];
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
gCtx.clearRect(0, 0, gCanvas.width, gCanvas.height);
qrcode.decode(e.target.result);
};
})(f);
reader.readAsDataURL(f);
}
But this doesn't work too :(
ORIGINAL POST
I have an input file to which a QR image file is supplied with.
<input type="file" onchange="doProcess(this.files)">
doProcess function
function doProcess(f)
{
var o=[];
for(var i =0;i<f.length;i++)
{
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
gCtx.clearRect(0, 0, gCanvas.width, gCanvas.height);
qrcode.decode(e.target.result);
};
})(f[i]);
reader.readAsDataURL(f[i]);
}
}
This function works perfectly. No problems there. The purpose of this function is to decode a QR image. Now out of sheer interest and curiosity, I'm planning to do something different - remove the need to browse to the image file manually. This brings me to a few queries:
Is it possible for doProcess(f) to perform the same actions when supplied with an image URL instead of a file? At present f parameter is a file. What will happen if f parameter is a URL (for ex: doProcess(http://www.abc.com/abc.jpg))? I realize there are other support functions inside doProcess() also being called to complete the decoding process but I'm assuming those will act accordingly to the type of data being passed through doProcess.
If f parameter is an image file (browsed on local computer and selected) instead of image URL, what data type will f be? I'm guessing it will be an array or in some raw binary form.
My intention is to study the process and know what exactly is happening behind the scenes. By using the 'browse' function, the QR image is being decoded successfully.
In summary, what will happen if I pass the location of the image stored as the argument instead of a file?
Thanks in advance.
There is some problems that I don't know you have or not in here because it's not your full code and I don't know what exactly you are trying to do. Here a working example of something very close of what you are doing. It loads a image on a canvas (you could use your qrcode stuff instead)
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
var gCanvas;
var gCtx;
function load(){
console.log("loaded");
gCanvas = document.getElementById("mcanvas");
if (gCanvas.getContext){
gCtx = gCanvas.getContext("2d");
} else console.log("no Canvas?");
}
function doProcess(f){
var o=[];
var reader = new FileReader();
reader.onload = (function(theFile) {
var img = new Image();
img.src = theFile;
img.onload = function(){
gCtx.clearRect(0, 0, gCanvas.width, gCanvas.height);
gCtx.drawImage(img,0,0);
}
return;
})(f);
console.log(reader);
reader.readAsDataURL(f);
}
</script>
</head>
<body onload="load()">
<input type="text" onClick="doProcess('https://www.google.com.br/logos/2012/clara_schuman-2012-hp.jpg')" />
<canvas id="mcanvas" height="500" width="500"></canvas>
</body>
</html>
dont't forget the load function, it grants your javascript to run after body loads.