Reloading a file using html input - javascript

I have a textarea that can, quite obviously, be edited using keyboard entry. I also want to be able to load a file using an html input. I have done so, using the onchange event. (jsfiddle code linked below).
Suppose I load a file using the file loader - which works correctly in the example.
Then, I edit this file. Realising that the changes I have made are not desired, I want to reload this file. However, when using the html input, nothing changes since the selected file remains the same (the onchange event is not triggered). Is there a way to reload a file using an html input. (The only workaround I have found is to load a different file, then reload the original file ... which is not very elegant).
http://jsfiddle.net/aroberge/8PZyK/1/
var load_file = function() {
$("#fileInput").show();
var fileInput = document.getElementById('fileInput');
fileInput.addEventListener('change', function(e) {
var file = fileInput.files[0];
var reader = new FileReader();
reader.onload = function(e) {
$("#editor").text(reader.result);
$("#fileInput").hide();
};
reader.readAsText(file);
});
};
$("#load").on("click", function(evt) {
load_file();
});

You could clear out the fileInput value after you've read the file from it:
updated fiddle:
http://jsfiddle.net/8PZyK/8/
var load_file = function() {
$("#fileInput").show();
var fileInput = document.getElementById('fileInput');
fileInput.addEventListener('change', function(e) {
if (fileInput.files && fileInput.files.length > 0) {
var file = fileInput.files[0];
var reader = new FileReader();
fileInput.value = "";
reader.onload = function(e) {
$("#editor").val(reader.result);
$("#fileInput").hide();
}
};
reader.readAsText(file);
});
};
$("#load").on("click", function(evt) {
load_file();
});

After the file input has changed, and you grab out the data, simple reset the input field like so:
fileInput.value = ""; // Or with jQuery, $('input[file]').val('')
This will trigger another change (which you'll want to ignore), but will allow the user to select the same file again and still give you a change event.

Related

Javascript Input Event Fire Twice

I want to upload an Excel file through the browser and I am showing this file. However sometimes there is an error and I need to change some columns in the Excel file and I want to upload the same file. The event is firing just one time because filename is the same. How can I solve this problem? I want to upload the same file and I want the event to fire twice.
document.getElementById('upload').addEventListener('input', handleFileSelect, false);
var handleFileSelect = function(evt) {
var files = evt.target.files; // FileList object
var xl2json = new ExcelToJSON();
xl2json.parseExcel(files[0]);
console.log(evt)
};
<input id="upload" type=file name="files[]">
I tried
$("#upload").unbind("input").bind("input",handleFileSelect)
and
document.getElementById('upload').addEventListener('change', handleFileSelect, false)
You should use the onChange event.
var el = document.getElementById('upload');
el.onchange = function() {
// your code...
};
I solved this problem. I added this code in my function
evt.target.value = null;

How can I display a text files contents in a textarea?

I am trying to create a file upload component, and display the text file contents in a textarea in the browser for editing before processing.
My inputs looks like this
<input type="file" process-file/>
<textarea id="file-text"
ng-model="fileContent">
</textarea>
I have a directive that correctly reads the file contents
app.directive('processFile', [function () {
return {
link: function (scope, element, attrs) {
element.on('change', function (evt) {
var files = evt.target.files;
var reader = new FileReader();
reader.onload = function(e) {
var text = e.target.result
console.log(text); // contents are correctly displayed
scope.fileContent = text; // this does not work
$scope.fileContent = text; // nor does this
$("#file-text").text(text) // or this
};
reader.readAsText(files[0]);
});
}
}
}]);
I need to inject the file content into that textarea but all attempts seem to fail. How can I do that?
Custom event considered as event runs out of angular context. After firing such event angular digest cycle system doesn't get intimated to update its bindings. You have to kick off digest cycle manually to sync up binding. You could use $timeout here to run digest cycle.
Code
element.on('change', function (evt) {
var files = evt.target.files;
var reader = new FileReader();
reader.onload = function(e) {
var text = e.target.result
console.log(text); // contents are correctly displayed
$timeout(function(){
scope.fileContent = text;
},0);
};
reader.readAsText(files[0]);
});
This is how you change value of a textarea:
document.getElementById('myTextarea').value = '';
or like this in jQuery:
$('#myTextarea').val('');
Where you have
<textarea id="myTextarea" name="something">This text gets removed</textarea>
How to change the Content of a <textarea> with Javascript
So should have this in your onload function:
$("#file-text").val(text);
Or this in your html file:
<textarea id="file-text">
{{fileContent}}
</textarea>

Vue - button on click submits a form

I have a component where a user can upload an image, and I would like to also add a feature of removing an image. I have added a button which removes the current image, but the problem with it is that the form is getting submitted as well, and I would like to avoid that. I just need to remove the current image if it exists. This is the script:
<template>
<div class="Image-input">
<div class="Image-input__input-wrapper">
<h2>+</h2>
<input #change="previewThumbnail" class="Image-input__input" name="image" type="file">
</div>
<div class="Image-input__image-wrapper">
<i v-show="! imageSrc" class="icon fa fa-picture-o"></i>
<img v-show="imageSrc" class="Image-input__image" :src="imageSrc">
<button v-show="imageSrc" #click="removeImage">Remove image</button>
</div>
</div>
</template>
<script>
export default {
props: ['imageSrc'],
methods: {
previewThumbnail: function(event) {
var input = event.target;
if (input.files && input.files[0]) {
var reader = new FileReader();
var vm = this;
reader.onload = function(e) {
vm.imageSrc = e.target.result;
}
reader.readAsDataURL(input.files[0]);
}
},
removeImage: function removeImage(e) {
this.imageSrc = '';
}
}
}
</script>
I have tried with placing event.preventDefault() in the removeImage method, but then, if I after removing image try to upload the same one again it won't upload. Not sure what to do about it?
If you have a button inside a form, it has a default type of "submit". To prevent that from happening, you will have to set type="button" as follows:
<button type="button" v-show="imageSrc" #click="removeImage">Remove image</button>
Reference: Can I make a <button> not submit a form?
Edit: Solution for the second problem mentioned in comments #1 to #5
Please modify your reader.onload function as follows:
reader.onload = function(e) {
vm.imageSrc = e.target.result;
console.log("Clearing file input");
document.querySelectorAll('input[type=file]').forEach(element => {
element.value = "";
});
}
As you can see, I am printing out a console log for debugging (which you can remove), then proceeding to select all file inputs and resetting its value. This clears the selected file.
Note: This clearing function happens after the file is read into memory. If you want it on remove function, you can do as follows:
removeImage: function removeImage(e) {
this.imageSrc = "";
console.log("Clearing file input");
document.querySelectorAll('input[type=file]').forEach(element => {
element.value = "";
});
}
The choice is yours, whether you want to clear the file name after reading into memory or if you want to keep it on screen. Let me know if it works!
Another note: If you have any other <input type="file"> in your app, even that will get cleared. But I assume you would have read it into memory and kept it in some local variables. To avoid this, you need to modify the document.querySelectorAll function to target only the relevant input by giving it a class or id.

Non-ajax post using Dropzone.js

I'm wondering if there's any way to make Dropzone.js (http://dropzonejs.com) work with a standard browser POST instead of AJAX.
Some way to inject the inputs type=file in the DOM right before submit maybe?
No. You cannot manually set the value of a <input type='file'> for security reasons. When you use Javascript drag and drop features you're surpassing the file input altogether. Once a file is fetched from the user's computer the only way to submit the file to the server is via AJAX.
Workarounds: You could instead serialize the file or otherwise stringify it and append it to the form as a string, and then unserialize it on the server side.
var base64Image;
var reader = new FileReader();
reader.addEventListener("load", function () {
base64Image = reader.result;
// append the base64 encoded image to a form and submit
}, false);
reader.readAsDataURL(file);
Perhaps you're using dropzone.js because file inputs are ugly and hard to style? If that is the case, this Dropzone.js alternative may work for you. It allows you to create custom styled inputs that can be submitted with a form. It supports drag and drop too, but with drag and drop you cannot submit the form the way you want. Disclaimer: I am author of aforementioned library.
So, if I understood correctly you want to append some data (input=file) before submit your form which has dropzone activated, right?
If so, I had to do almost the same thing and I got it through listening events. If you just upload one file, you should listen to "sending" event, but if you want to enable multiple uploads you should listen to "sendingmultiple". Here is a piece of my code that I used to make this work:
Dropzone.options.myAwesomeForm = {
acceptedFiles: "image/*",
autoProcessQueue: false,
uploadMultiple: true,
parallelUploads: 100,
maxFiles: 100,
init: function() {
var myDropzone = this;
[..some code..]
this.on("sendingmultiple", function(files, xhr, formData) {
var attaches = $("input[type=file]").filter(function (){
return this.files.length > 0;
});
var numAttaches = attaches.length;
if( numAttaches > 0 ) {
for(var i = 0; i < numAttaches; i++){
formData.append(attaches[i].name, attaches[i].files[0]);
$(attaches[i]).remove();
}
}
});
[..some more code..]
}
}
And that's it. I hope you find it helpful :)
PS: Sorry if there's any grammar mistakes but English is not my native language
For future visitors
I've added this to dropzone options:
addedfile: function (file) {
var _this = this,
attachmentsInputContainer = $('#attachment_images');
file.previewElement = Dropzone.createElement(this.options.previewTemplate);
file.previewTemplate = file.previewElement;
this.previewsContainer.appendChild(file.previewElement);
file.previewElement.querySelector("[data-dz-name]").textContent = file.name;
file.previewElement.querySelector("[data-dz-size]").innerHTML = this.filesize(file.size);
if (this.options.addRemoveLinks) {
file._removeLink = Dropzone.createElement("<a class=\"dz-remove\" href=\"javascript:undefined;\">" + this.options.dictRemoveFile + "</a>");
file._removeLink.addEventListener("click", function (e) {
e.preventDefault();
e.stopPropagation();
if (file.status === Dropzone.UPLOADING) {
return Dropzone.confirm(_this.options.dictCancelUploadConfirmation, function () {
return _this.removeFile(file);
});
} else {
if (_this.options.dictRemoveFileConfirmation) {
return Dropzone.confirm(_this.options.dictRemoveFileConfirmation, function () {
return _this.removeFile(file);
});
} else {
return _this.removeFile(file);
}
}
});
file.previewElement.appendChild(file._removeLink);
}
attachmentsInputContainer.find('input').remove();
attachmentsInputContainer.append(Dropzone.instances[0].hiddenFileInput).find('input').attr('name', 'files');
return this._updateMaxFilesReachedClass();
},
This is default implementation of dropzone's addedfile option with 3 insertions.
Declared variable attachmentsInputContainer. This is invisible block. Something like
<div id="attachment_images" style="display:none;"></div>
Here I store future input with selected images
Then in the end of function remove previously added input(if any) from block and add new
attachmentsInputContainer.find('input').remove();
attachmentsInputContainer.append(Dropzone.instances[0].hiddenFileInput).find('input').attr('name', 'files');
And now, when you send form via simple submit button, input[name="files"] with values will be send.
I've made this hack because I append files to post that maybe not created yet
This is what I used for my past projects,
function makeDroppable(element, callback) {
var input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('multiple', true);
input.style.display = 'none';
input.addEventListener('change', triggerCallback);
element.appendChild(input);
element.addEventListener('dragover', function(e) {
e.preventDefault();
e.stopPropagation();
element.classList.add('dragover');
});
element.addEventListener('dragleave', function(e) {
e.preventDefault();
e.stopPropagation();
element.classList.remove('dragover');
});
element.addEventListener('drop', function(e) {
e.preventDefault();
e.stopPropagation();
element.classList.remove('dragover');
triggerCallback(e);
});
element.addEventListener('click', function() {
input.value = null;
input.click();
});
function triggerCallback(e) {
var files;
if(e.dataTransfer) {
files = e.dataTransfer.files;
} else if(e.target) {
files = e.target.files;
}
callback.call(null, files);
}
}

Javascript: onload event not reaching for javascript's FileReader API

I need to create extract the signature of a file at the client level itself so as to positively determine its file type. Below is my file input object:
<input id="test1" type="file">
I wrote the following javascript code against it:
var fileInput = document.getElementById('test1');
fileInput.addEventListener('change', function(e) {
console.log("file selected");
var reader = new FileReader();
reader.onload = function(e) {
console.log("loaded");
var file_slice = gcUploadFile.slice(0,4);
console.log(file_slice);
var arr_buffer = reader.readAsArrayBuffer(file_slice);
console.log(arr_buffer);
}
});
Check out the fiddle for the above.
The trouble I am having is that my code does not even enters the onload fucntion.
What am i doing wrong?
Note: I am coding only using plain javascript but i am open to use Google Closure.
Why would it reach the onload handler, nothing is ever read by the FileReader.
You have to pass the file to the fileReader by reading it as something
var fileInput = document.getElementById('test1');
fileInput.addEventListener('change', function(e) {
console.log("file selected");
var reader = new FileReader();
reader.onload = function(e) {
console.log("loaded");
var file_slice = gcUploadFile.slice(0,4);
console.log(file_slice);
var arr_buffer = reader.readAsArrayBuffer(file_slice);
console.log(arr_buffer);
}
reader.readAsBinaryString(e.target.files[0]);
});

Categories