How FileReader.readAsText in HTML5 File API works? - javascript

I wrote the following code to check whether the uploaded file exists or not using HTML5 file API.
<input type="file" id="myfile">
<button type="button" onclick="addDoc()">Add Document</button>
<p id="DisplayText"></p>
The following JavaScript code has been mapped to it is as follows:
function addDoc() {
var file=document.getElementById("myFile").files[0]; //for input type=file
var reader=new FileReader();
reader.onload = function(e) {}
reader.readAsText(file);
var error = reader.error;
var texte=reader.result;
document.getElementById("DisplayText").innerText=reader.result; /*<p id="DisplayText>*/
}
After browsing a file from local system I tried to delete the "browsed" document form the folder before clicking on addDoc(). After clicking the button I could still see Filereader.result is not null and could display all the content.
Can someone explain on how the Filereader works? Is it that the FileReader gets bound as soon as the file is browsed?
Also can we check whether the system Readonly Attribute with FileReader similar to Java File.canread()?
Could someone suggest on this? I have IE11 to test the code.

FileReader load event sets the .result value asynchronously. To access the .result use load or loadend event.
When a file has been selected at <input type="file"> Choose File or Browse... UI, deleting file at local filesystem should not effect the File object at FileList returned by .files call. See 2.9.2. Transferable objects, 6.7.3 The DataTransfer interface.
4. The Blob Interface and Binary Data
Each Blob must have an internal snapshot state, which
must be initially set to the state of the underlying storage, if any
such underlying storage exists, and must be preserved through
structured clone. Further normative definition of snapshot state can be found for Files.
2.9.8 Monkey patch for Blob and FileList objects
This monkey patch will be removed in due course. See w3c/FileAPI
issue 32.
Blob objects are cloneable objects.
Each Blob object's [[Clone]] internal method, given targetRealm and ignoring memory, must run these steps:
If this is closed, then throw a "DataCloneError" DOMException.
Return a new instance of this in targetRealm, corresponding to
the same underlying data.
FileList objects are cloneable objects.
Each FileList object's [[Clone]] internal method, given
targetRealm and memory, must run these steps:
Let output be a new FileList object in targetRealm.
For each file in this, add ? [StructuredClone][15](_file, targetRealm, memory_) to the end of the list of File objects
of output.
Return output.
Selecting read-only files or folders at webkit and firefox browsers
At chrome, chromium if read-only permission is set for file at local filesystem and user selects file at <input type="file"> element, where FileReader is used to read file, an error is thrown at FileReader, generated from FileReader progress event.
If a Blob URL is set to the same file object, the blob: URL will not return the the read-only file at request to the Blob URL.
Selection of folder where folder permission is set to read-only
Chrome, chromium
At chrome, chromium where webkitdirectory attribute is set and folder is selected with read-only permission FileList .length of event.target.files returned 0; event.target.files.webkitGetAsEntry() is not called, "No file chosen" is rendered at <input type="file"> shadowDOM. When a folder is dropped at <input type="file"> or element where droppable attribute set, the directory .name and .path of the read-only folder is displayed at drop event.dataTransfer.
When user drops file or folder at <textarea> element, where no drop event is attached beforeunload event is called and a prompr is displayed at UI
Do you want to leave this site?
Changes you made may not be saved.
<Stay><Leave> // <buttons>
Firefox
At firefox version 47.0b9 with allowdirs attribute is set at <input type="file"> element, where user clicks "Choose folder.." <input>, the folder .name and .path of the parent folder are accessible at .then() chained to event.target.getFilesAndDirectories(). The files or folders contained within the selected folder are not returned when recursively iterating Directory entries; an an empty string is returned.
If user clicks "Choose file..." <input> and a folder is selected without read-only permission set, when the folder at file manager is clicked, the files in the folder are listed.
Where a folder is selected where read-only permission is set an alert() notification is rendered at UI displaying
Could not read the contents of <directory name>
Permission denied
Bug, security issue
*nix OS
When user drops folder at <textarea> element, where no drop event is attached, the full path to the folder at user filesystem file: protocol is exposed. The paths to the files contained within the folder are not also set as .value; e.g.,
"file:///home/user/Documents/Document/"
When a file is dropped at <textarea> element, where not drop event is attached, the full path to the file at user filesystem is set as .value of <textarea>; that is,
"file:///home/user/Documents/Document/MyFileFullPathDisplayedAtTextAreaValue.txt"
If multiple files are selected and dropped at <textarea> element, all of the full file paths are set as .value of <textarea>, delineated by new line character \n
"file:///home/user/Documents/Document/MyFileFullPathDisplayedAtTextAreaValue1.txt"
"file:///home/user/Documents/Document/MyFileFullPathDisplayedAtTextAreaValue2.txt"
..
Where an XMLHttpRequest() is made for the file path and error is logged at console
NS_ERROR_DOM_BAD_URI: Access to restricted URI denied
When set as .src of an <img> element with .crossOrigin set to "anonymous" the img error event handler is called
At call to window.open() with full path set at first parameter
Error: Access to '"file:///home/user/Documents/Document/MyFileFullPathDisplayedAtTextAreaValue.png"' from script denied
Specification
4.10.5.1.18. File Upload state (type=file)
EXAMPLE 16
For historical reasons, the value IDL attribute prefixes the
file name with the string "C:\fakepath\". Some legacy user agents
actually included the full path (which was a security vulnerability).
As a result of this, obtaining the file name from the value IDL
attribute in a backwards-compatible way is non-trivial.
4.10.5.4. Common <input> element APIs
filename
On getting, it must return the string "C:\fakepath\" followed by the name of the first file in the list of selected
files, if any, or the empty string if the list is empty. On
setting, if the new value is the empty string, it must empty the list
of selected files; otherwise, it must throw an "InvalidStateError"
DOMException.
NOTE: This "fakepath" requirement is a sad accident of history. See the example in the File Upload state section for more
information.
NOTE: Since path components are not permitted in file names in the list of selected files, the "\fakepath\" cannot be mistaken
for a path component.
4.10.5.1.18. File Upload state (type=file)
Path components
When an <input> element’s type attribute is in the File Upload
state, the rules in this section apply.
The <input> element represents a list of selected files,
each file consisting of a file name, a file type, and a file body (the
contents of the file).
File names must not contain path components, even in the case that a
user has selected an entire directory hierarchy or multiple files with
the same name from different directories. Path components, for the
purposes of the File Upload state, are those parts of file names
that are separated by U+005C REVERSE SOLIDUS character () characters.
Bug report https://bugzilla.mozilla.org/show_bug.cgi?id=1311823
Dropping file at <textarea> at data URI
Following comment by Neal Deakin at bug report
I think the steps referred to are:
Open data:text/html,
Drag a file from the desktop to the textarea
I can reproduce this on Linux, but not on Windows or Mac.
The hunch above is correct; Linux is including the data as a url and
plaintext as well.
dropped files at data: prototcol data URI at firefox, and chrome, chromium
data:text/html,<textarea></textarea>
Firefox
The full path name of file or folder set as .value of <textarea>.
Chrome, chromium
Dropping file at data URI having only textarea element at chrome, chromium replaces the data URI with dropped file path at address bar, and loads the dropped file at the same tab, replacing the data URI with the content of the dropped file.
plnkr http://plnkr.co/edit/ZfAGEAiyLLq8rGXD2ShE?p=preview
html, javascript to reproduce issue described above
<!DOCTYPE html>
<html>
<head>
<style>
body {
height: 400px;
}
textarea {
width: 95%;
height: inherit;
}
</style>
<script>
window.onload = function() {
var button = document.querySelector("#myfile + button");
var input = document.getElementById("myfile");
var display = document.getElementById("DisplayText");
var text = null;
function readFullPathToFileOnUserFileSystem(e) {
var path = e.target.value;
console.log(path);
var w = window.open(path, "_blank");
var img = new Image;
img.crossOrigin = "anonymous";
img.onload = function() {
document.body.appendChild(this);
}
img.onerror = function(err) {
console.log("img error", err.message)
}
img.src = path;
var request = new XMLHttpRequest();
request.open("GET", path.trim(), true);
request.onload = function() {
console.log(this.responseText)
}
request.error = function(err) {
console.log(err.message)
}
request.send();
}
display.addEventListener("input", readFullPathToFileOnUserFileSystem);
input.addEventListener("change", addDoc);
input.addEventListener("progress", function(event) {
console.log("progress", event)
});
button.addEventListener("click", handleText)
function addDoc(event) {
var mozResult = [];
function mozReadDirectories(entries, path) {
console.log("dir", entries, path);
return [].reduce.call(entries, function(promise, entry) {
return promise.then(function() {
console.log("entry", entry);
return Promise.resolve(entry.getFilesAndDirectories() || entry)
.then(function(dir) {
console.log("dir getFilesAndDirectories", dir)
return dir
})
})
}, Promise.resolve())
.catch(function(err) {
console.log(err, err.message)
})
.then(function(items) {
console.log("items", items);
var dir = items.filter(function(folder) {
return folder instanceof Directory
});
var files = items.filter(function(file) {
return file instanceof File
});
if (files.length) {
console.log("files:", files, path);
mozResult = mozResult.concat.apply(mozResult, files);
}
if (dir.length) {
console.log(dir, dir[0] instanceof Directory, dir[0]);
return mozReadDirectories(dir, dir[0].path || path);
} else {
if (!dir.length) {
return Promise.resolve(mozResult).then(function(complete) {
return complete
})
}
}
})
.catch(function(err) {
console.log(err)
})
};
console.log("files", event.target.files);
if ("getFilesAndDirectories" in event.target) {
return (event.type === "drop" ? event.dataTransfer : event.target)
.getFilesAndDirectories()
.then(function(dir) {
if (dir[0] instanceof Directory) {
console.log(dir)
return mozReadDirectories(dir, dir[0].path || path)
.then(function(complete) {
console.log("complete:", complete);
event.target.value = null;
});
} else {
if (dir[0] instanceof File && dir[0].size > 0) {
return Promise.resolve(dir)
.then(function(complete) {
console.log("complete:", complete);
})
} else {
if (dir[0].size == 0) {
throw new Error("could not process '" + dir[0].name + "' directory" + " at drop event at firefox, upload folders at 'Choose folder...' input");
}
}
}
}).catch(function(err) {
console.log(err)
})
}
var reader = new FileReader();
reader.onload = function(e) {
text = reader.result;
console.log("FileReader.result", text);
button.removeAttribute("disabled");
}
reader.onerror = function(err) {
console.log(err, err.loaded, err.loaded === 0, file);
button.removeAttribute("disabled");
}
reader.onprogress = function(e) {
console.log(e, e.lengthComputable, e.loaded, e.total);
}
reader.readAsArrayBuffer(file);
}
function handleText() {
// do stuff with `text`: `reader.result` from `addDoc`
display.textContent = text;
button.setAttribute("disabled", "disabled");
// set `text` to `null` if not needed or referenced again
text = null;
}
}
</script>
</head>
<body>
<input type="file" id="myfile" webkitdirectory directory allowdirs>
<button type="button" disabled>Add Document</button>
<br>
<br>
<textarea id="DisplayText"></textarea>
</body>
</html>
plnkr http://plnkr.co/edit/8Ovw3IlYKI8BYsLhzV88?p=preview
You can use change event attached to #myfile element to handle file selection action by user.
Substitute <textarea> element for <p> element to display result of load event from .readAsText() call.
To display .result of FileReader at click at button element, set variable text to reader.result within load event of FileReader at click event at button set .textContent of #DisplayText element to variable referencing previously set reader.result.
<!DOCTYPE html>
<html>
<style>
body {
height: 400px;
}
textarea {
width:95%;
height: inherit;
}
</style>
<head>
<script>
window.onload = function() {
var button = document.querySelector("#myfile + button");
var input = document.getElementById("myfile");
var display = document.getElementById("DisplayText");
var text = null;
input.addEventListener("change", addDoc);
button.addEventListener("click", handleText)
function addDoc(event) {
var file = this.files[0]
var reader = new FileReader();
reader.onload = function(e) {
text = reader.result;
button.removeAttribute("disabled");
}
reader.onerror = function(err) {
console.log(err, err.loaded
, err.loaded === 0
, file);
button.removeAttribute("disabled");
}
reader.readAsText(event.target.files[0]);
}
function handleText() {
// do stuff with `text`: `reader.result` from `addDoc`
display.textContent = text;
button.setAttribute("disabled", "disabled");
// set `text` to `null` if not needed or referenced again
text = null;
}
}
</script>
</head>
<body>
<input type="file" id="myfile" accept="text/*">
<button type="button" disabled>Add Document</button><br><br>
<textarea id="DisplayText"></textarea>
</body>
</html>

The FileReader object lets web applications asynchronously read the contents of files (or raw data buffers) stored on the user's computer, using File or Blob objects to specify the file or data to read.
File objects may be obtained from a FileList object returned as a result of a user selecting files using the element, from a drag and drop operation's DataTransfer object, or from the mozGetAsFile() API on an HTMLCanvasElement.
The readAsText method is used to read the contents of the specified Blob or File. When the read operation is complete, the readyState is changed to DONE, the loadend is triggered, and the result attribute contains the contents of the file as a text string.
Syntax
instanceOfFileReader.readAsText(blob[, encoding]);
Parameters
Blob
The Blob or File from which to read.
encoding Optional
A string specifying the encoding to use for the returned data. By default, UTF-8 is assumed if this parameter is not specified.
For the metadata about a file we can check the File object F such that:
F has a readability state of OPENED.
F refers to the bytes byte sequence.
F.size is set to the number of total bytes in bytes.
F.name is set to n.
F.type is set to t.
Note: The type t of a File is considered a parsable MIME type if the ASCII-encoded string representing the File object's type, when
converted to a byte sequence, does not return undefined for the parse
MIME type algorithm [MIMESNIFF].
F.lastModified is set to d.
See more about browser compatibility and detailed document for FileReader, File and readAsText at MDN, also this W3C draft for FileApi

Use this instead:-
function loadFileAsText()
{
var fileToLoad = document.getElementById("fileToLoad").files[0];
var fileReader = new FileReader();
fileReader.onload = function(fileLoadedEvent)
{
var textFromFileLoaded = fileLoadedEvent.target.result;
document.getElementById("inputTextToSave").innerText = textFromFileLoaded;
};
fileReader.readAsText(fileToLoad, "UTF-8");
}
<p>Select a File to Load:</p>
<input type="file" id="fileToLoad"><button onclick="loadFileAsText()">Load Selected File</button>
<br>
<br>
<br>
<p>Text file loaded:</p>
<p id="inputTextToSave"></p>

Related

I want to extract a string from a text file and output it as a text file again

I want to extract a string from a text file, convert it to a word scrambler (I figured out that part) and output it in another text file.
I found some code to input a text file and extract the text:
<html>
<h4>Select un file con .txt extension</h4>
<input type="file" id="myFile" accept=".txt" />
<br /><br />
<div id="output"></div>
<script>
var input = document.getElementById("myFile");
var output = document.getElementById("output");
input.addEventListener("change", function () {
if (this.files && this.files[0]) {
var myFile = this.files[0];
var reader = new FileReader();
reader.addEventListener("load", function (e) {
output.textContent = e.target.result;
});
reader.readAsText(myFile);
}
});
</script>
</html>
Input text and extract a text file
<html>
<div>
<input type="text" id="txt" placeholder="Write Here" />
</div>
<div>
<input type="button"id="bt"value="Save in a File"onclick="saveFile()"/>
</div>
<script>
let saveFile = () => {
const testo = document.getElementById("txt");
let data = testo.value;
const textToBLOB = new Blob([data], { type: "text/plain" });
const sFileName = "Testo.txt";
let newLink = document.createElement("a");
newLink.download = sFileName;
newLink.href = window.URL.createObjectURL(textToBLOB);
newLink.style.display = "none";
document.body.appendChild(newLink);
newLink.click();
};
</script>
</html>
But I don't know how to output a string in the first code or how to connect it to the second code. Could someone please show me how to do it or explain how these codes work so that I could try to do it myself in JavaScript?
I will comment each line of JavaScript, that should help you understand.
<script>
/*This creates a global variable with the HTML element input in it. */
var input = document.getElementById("myFile");
/*This creates a global variable with the HTML element div with id output in it. */
var output = document.getElementById("output");
/* this 2 lines are used to set the source and the destination.
The first will get where you put your file, in this case it's the input element.
The second will get the div which content will be replaced by the content of your txt file. */
/* Here we tell to our input element to do something special when his value changes.
A change will occur for example when a user will chose a file.*/
input.addEventListener("change", function () {
/* First thing we do is checking if this.files exists and this.files[0] aswell.
they might not exist if the change is going from a file (hello.txt) to no file at all */
if (this.files && this.files[0]) {
/* Since we can chose more than one file by shift clicking multiple files, here we ensure that we only take the first one set. */
var myFile = this.files[0];
/* FileReader is the Object in the JavaScript standard that has the capabilities to read and get informations about files (content, size, creation date, etc) */
var reader = new FileReader();
/* Here we give the instruction for the FileReader we created, we tell it that when it loads, it should do some stuff. The load event is fired when the FileReader reads a file. In our case this hasn't happened yet, but as soon as it will this function will fire. */
reader.addEventListener("load", function (e) {
/* What we do here is take the result of the fileReader and put it inside our output div to display it to the users. This is where you could do your scrambling and maybe save the result in a variable ? */
output.textContent = e.target.result;
});
/* This is where we tell the FileReader to open and get the content of the file. This will fire the load event and get the function above to execute its code. */
reader.readAsText(myFile);
}
});
</script>
With this I hope you'll be able to understand the first part of this code. Try putting the second part of your code instead of output.textContent and replacing data with e.target.result, that should do what you wish, but I'll let you figure it out by yourself first, comment on this answer if you need further help !
Here's a codepen with working and commented code:
https://codepen.io/MattDirty/pen/eYZVWyK

Get the image as file in angular

I am making angular application with image upload option which has the,
Html :
<label class="hoverable" for="fileInput">
<img [src]="url ? url : avatarImage">
<div class="hover-text">Choose file</div>
<div class="background"></div>
</label>
<br/>
<input id="fileInput" type='file' (change)="onSelectFile($event)">
<button *ngIf="url" (click)="delete()" >delete</button>
<img (click)="uploadPersonaImage($event)" class="avatar-images" src="https://www.w3schools.com/howto/img_avatar.png">
<img (click)="uploadPersonaImage($event)" class="avatar-images" src="https://www.w3schools.com/howto/img_avatar2.png">
Here what i am having is if the user clicks over the image he can select and update whatever image he has in local.
Same way if the user was not interested to update the profile image but interested to select any of the avatar image as per his/her wish which i have given like,
<img (click)="uploadPersonaImage($event)" class="avatar-images" src="https://www.w3schools.com/howto/img_avatar.png">
<img (click)="uploadPersonaImage($event)" class="avatar-images" src="https://www.w3schools.com/howto/img_avatar2.png">
And in ts made something like this,
uploadPersonaImage(e) {
this.url = e.target.src;
}
So on the click function the src that comes from the event.target was set to this.url..
But i need to convert it as file.. Because i need to send it as file to the service call so i need to update the avatar image.
So please help me to convert the avatar image selected/clicked by the user to the file/formdata so that it can be sent to the service as file format and can be updated as user selected image..
Example: https://stackblitz.com/edit/angular-file-upload-preview-85v9bg
You can use FormData to attach the read file and send to the API.
onSelectFile(event) {
if (event.target.files && event.target.files[0]) {
this.uploadToServer(event.target.files[0]);
... rest of the code
}
uploadToServer(file) {
let formData: FormData = new FormData();
formData.append('fileName', file);
// call your api service to send it to server, send formData
}
EDIT:
Try this out if you have no option to touch onSelectFile() or trigger a different function when you upload the file.
_url = ''
set url(val) {
this._url = val;
if (val) {
this.dataURLtoFile(val);
}
}
get url() {
return this._url;
}
uploadedImage: File ;
dataURLtoFile(dataurl) {
const arr = dataurl.split(',');
const mime = arr[0].match(/:(.*?);/)[1];
const imageExtension = mime.split('/')[1];
const bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
this.uploadedImage = new File([u8arr], `uploaded.${imageExtension}`);
}
On your API call, maybe when you click on a button,
uploadPersonaImage(e) {
// this.apiService.someMethod(this.uploadedImage);
}
If you want to trigger the API call just when you upload the image, add the code of dataURLtoFile() to uploadPersonaImage() and call uploadPersonaImage() from url setter
Clarification
Do you understand what does event.target.src mean (considering e as event)?
Here event means the click/change event you triggered when you
clicked onto upload photo.
event.target means the DOM element on which the event took place.
event.target.src will give you the src attribute value of the
DOM element on which you triggered the change event.
Now, you say won't it work? No, it won't because the element which you clicked is an HTMLInputElement but the src resides under the image in under the label tag. And how are you intending to call uploadPersonaImage()? what calls your method? You haven't answered that even after asking so many times.
In my last edit, I have added code under the setter of the url which will convert the dataUrlFile to an actual File, It completely depends on your server how you want to store the file. As a file or as a dataUrl? If you want to send it as a file then follow the conversions I added in the answer if you want to save as dataUrl then directly save the content of this.url on your API call.

JavaScript delete File from FileList to be uploaded

There is the code https://jsfiddle.net/bfzmm1hc/1 Everything looks fine but I want to delete some of the files from the set.
I have already found these:
How to remove one specific selected file from input file control
input type=file multiple, delete items
I know that FileList object is readonly, so I can just copy the files to a new array. But what should I do with this new array of File objects? I can't assign it to the files property...
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..
Since you cannot edit the Read Only input.files attribute, you must upload a form using XMLHttpRequest and send a FormData object. I will also show you how to use URL.createObjectURL to more easily get a URI from the File object:
var SomeCl = {
count: 0,
init: function() {
$('#images').change(this.onInputChange);
},
onInputChange: function() {
// reset preview
$('.container').empty();
// reset count
SomeCl.count = 0;
// process files
SomeCl.processFiles(this.files, function(files) {
// filtered files
console.log(files);
// uncomment this line to upload the filtered files
SomeCl.upload('url', 'POST', $('#upload').get(0), files, 'images[]');
});
},
processFiles: function(files, callback) {
// your filter logic goes here, this is just example
// filtered files
var upload = [];
// limit to first 4 image files
Array.prototype.forEach.call(files, function(file) {
if (file.type.slice(0, 5) === 'image' && upload.length < 4) {
// add file to filter
upload.push(file);
// increment count
SomeCl.count++;
// show preview
SomeCl.preview(file);
}
});
callback(upload);
},
upload: function(method, url, form, files, filename) {
// create a FormData object from the form
var fd = new FormData(form);
// delete the files in the <form> from the FormData
fd.delete(filename);
// add the filtered files instead
fd.append(filename, files);
// demonstrate that the entire form has been attached
for (var key of fd.keys()) {
console.log(key, fd.getAll(key));
}
// use xhr request
var xhr = new XMLHttpRequest();
xhr.open(method, url, true);
xhr.addEventListener('progress', function(e) {
console.log('lengthComputable', e.lengthComputable);
console.log(e.loaded + '/' + e.total);
});
xhr.addEventListener('load', function(e) {
console.log('uploaded');
});
xhr.addEventListener('error', function(e) {
console.log('this is just a demo');
});
xhr.send(fd);
},
preview: function(file) {
// create a temporary URI from the File
var url = URL.createObjectURL(file);
// append a preview
$('.container').append($('<img/>').attr('src', url));
}
};
SomeCl.init();
.container img {
max-width: 250px;
max-height: 250px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="upload">
<input name="other" type="hidden" value="something else">
<input name="images[]" id="images" multiple="multiple" type="file">
<div class="container"></div>
</form>

How do I upload and process a file in Javascript?

I am creating a small html5 app that will allow users to change color properties of some elements. I want to give the user the option to save their changes and then upload them on later occasion (without registration). For this, I added a button that produces a text file of their properties, I want to add a button that will allow them to upload the file, I created a file picker dialog,
<label>
<input class="button"
type="file"
name="input-name"
style="display:none;"
onchange="read(event)"/>
<span id="input-file" >Select File</span>
</label>
But I can't figure how do I open this file in javascript and process its content. I know this should be similar to this
function read(evt){
var file = document.getElementById("input-file");
//checking for file reader
if (window.File && window.FileReader && window.FileList && window.Blob){
var r = new FileReader();
r.readAsText(file);
} else{
alert("Browser not supported");
}
}
But this doesn't work because file above is not the path to the file but the object. How do I get the path to the file? Is there a better way to do this?
You can read files via the File API, but you can't save them. You can create windows containing the text you want to save and then let the user save it, but it's a pain both when saving and loading.
Fortunately, for what you're talking about, you don't want files.
Instead, store the color preferences in web storage, specifically localStorage:
Loading (e.g., on page load or whenever):
var savedColor = localStorage.getItem("saved-color");
if (savedColor == null) {
// There wasn't one, use a default
}
Saving:
localStorage.setItem("saved-color", savedColor);
(localStorage in the above isn't a placeholder or anything; it's a global that's present on browsers that support local storage, which is [just about all of them2.)
Web storage values are always strings. You can use JSON if you need to store complex things.
Assuming your text file is in JSON (stringified format), i.e. your file.txt contains {"primary":"green","secondary":"#FF0000"}
<input type="file" id="file-picker" accept="text/plain" />
/*
Assuming JSON format in the text file - e.g:
var colors = {
primary: 'green',
secondary: '#FF0000'
}
JSON.stringify(colors);
output: '{"primary":"green","secondary":"#FF0000"}'
*/
var fileInput = document.querySelector('#file-picker');
function readFileJSON(file) {
return new Promise(function(resolve) {
var reader = new FileReader();
reader.onload = function(e) {
try {
resolve(JSON.parse(e.target.result));
} catch(ex) {
throw ex;
}
};
reader.readAsText(file);
});
}
fileInput.addEventListener('change', function(e) {
var file = e.target.files.item(0);
if (!file) {
return;
}
readFileJSON(file).then(function(colors) {
console.log('Colors:', colors);
});
});
JSBIN: https://jsbin.com/weriguhato/edit?html,js,output

HTML5 Drag & Drop File Upload gets JavaScript 'permission denied' accessing FileInfo object

I'm trying to upload a single file using standard multipart upload. It should work just as if there was a form on the page with a file field and a text field and a submit button at the bottom. They identify the file, type in a few other strings and click the "upload" button. In this case, though the form is just a dummy used to create a FileForm object. And the text field and file field and drop box are just random DOM elements with JS behind them. (HTML and jQuery/JavaScript below.)
So, concerning the non-form code, it works (meaning the file uploads and I can see the bytes on the server) only if the user uses the <input type="file" .../> element to identify the file.
If the user does a drag and drop of a file onto a spot on the page, I save the file info in a data element and use it from there instead of from the file input field. But when a file is dropped, an error (shown below) occurs because the code isn't allowed to get a single file out of the FileList returned by the drop.
So I put all the relevant code here and set up a fiddle. But, when I strip it down to the jsFiddle (linked below), both methods work.
That truly messes up the whole question. But I'm going to submit it anyway because it has code pulled together and simplified from a lot of older SO questions for doing file uploads and drag & drop. Plus someone might know what could cause the error.
Question: What sorts of things should I look for on my full page that would cause the contents of the dropped FileInfo object to become protected? That's the question for now.
Here's the FIDDLE
Here's the error message:
Error: Permission denied to access property 'length'
if (files.length > 1) {
Here's the HTML
<label for="dropbox">
<span>DROP HERE:</span>
<!-- CSS makes this a big purple bordered box -->
<div id="dropbox"> </div>
<div id="dropfile"></div>
</label>
<label for="inputFile">
<span>FILES:</span>
<input type="file" id="inputFile" name="inputFile"/>
</label>
<input type="button" id="upload" value="Upload"/>
<form enctype="multipart/form-data" method="post" id="fileform"></form>
Here's the JS w/ jQuery
$.event.props.push('dataTransfer');
$("#dropbox").on("drop", function(e) {
e.stopPropagation();
e.preventDefault();
var dt = e.originalEvent.dataTransfer;
var files = dt.files;
// errors on these lines *******************************************
if (files.length > 1) { alert(files.length + " files dropped. Only 1 allowed"); }
var file = files[0];
// errors on these lines *******************************************
$("#dropfile").text(file.name);
$("#dropbox").data("file", file);
try {
$("#inputFile").val(""); // works in some browsers
} catch (e) {
// ignore failure in some browsers
}
});
$("#dropbox").on("dragenter", function(e) {
e.stopPropagation();
e.preventDefault();
});
$("#dropbox").on("dragover", function(e) {
e.stopPropagation();
e.preventDefault();
});
$("#inputFile").change(function(e) { // selecting a file, erases dropped one
$("#dropfile").text("");
$("#dropbox").removeData("file");
});
$("#upload").click(function() {
var data = new FormData($("#fileform")[0]);
var obj = readTextBoxes();
for (var prop in obj) {
data.append(prop, obj[prop]);
}
// HTML file input user's choice(s)...
var dropfile = $("#dropbox").data("file");
if (dropfile) {
data.append("inputFile", dropfile);
} else {
$.each($("#inputFile")[0].files, function(i, file) {
data.append("inputFile[" + i + "]", file);
});
}
var parms = {
url : baseUrl + "v2/document/upload",
type : "POST",
processData: false, // tell jQuery not to process the data
contentType: false, // tell jQuery not to set contentType
data : data,
timeout : 40000
};
var promise = $.ajax(parms);
// ... handle response
});

Categories