Displaying picture before submitting the form JavaScript [duplicate] - javascript

This question already has answers here:
Preview an image before it is uploaded
(29 answers)
Closed 2 years ago.
I'd like to prepare a profile picture upload form. What's necessary here? Ability to see how is the image going to fit, before submitting it which is the moment I'm stuck at unfortunately. I attached here the form element from my JSP and JS file supposed to handle retrieving the form file via formData.
For some reason tho JS isn't willing to do anything with the backgroundImage property not throwing any kind of error either.
I'd really love some help with this task.
Using plain languages only, as I'm an extremist ;).
HTML:
<div class="profilePicture">
<form class="choosePhotoLabel" enctype="multipart/form-data" action="savePictureServlet" method="post">
<input class="choosePhoto" type="file" name="picture">
<input class="photoOk" type="submit" value="this is the picture!">
</form>
</div>
JavaScript:
document.addEventListener("DOMContentLoaded", function () {
let formInHTML = document.getElementsByClassName("choosePhotoLabel").item(0);
let formInputInHTML = document.getElementsByClassName("choosePhoto").item(0);
let imagePlace = document.getElementsByClassName("profilePicture").item(0);
let pictureReader = new FileReader();
function mlemToFile(mlem) {
mlem.lastModifiedDate = new Date();
mlem.name = "nonMlemPicture";
return mlem;
}
formInputInHTML.addEventListener("change", function () {
let formData = new FormData(formInHTML);
let formPicture = formData.get("picture");
if (formPicture != null) {
let nonMlemPicture = mlemToFile(formPicture);
pictureReader.readAsDataURL(nonMlemPicture);
if (pictureReader.result != null) {
let picture64 = pictureReader.result.replace(/^data:.+;base64,/, '');
imagePlace.style.backgroundImage = picture64;
}
}
});
});

The FileReader is async, which means you have to wait for the result to have been read.
you are missing:
pictureReader.onload = function () {
// code to set the image source
}
also you shouldn't remove the prefix (data:.+;base64) in the beginning - that part is important
But i don't think you should be using the filereader to display base64 images. It's better & faster to use object url referring to the blob/file in it's binary form.
also, instead of using formdata, use formInputInHTML.files[0]
formInputInHTML.addEventListener("change", function () {
const formPicture = formInputInHTML.files[0];
const url = URL.createObjectURL(formPicture);
imagePlace.style.backgroundImage = `url(${url})`;
});

short solution
let uploadInput = document.getElementById("uploadInput");
uploadInput.onchange = function () {
let image = new FileReader();
image.onload = function (e) {
document.getElementById("imagePreview").src = e.target.result;
};
image.readAsDataURL(this.files[0]);
};
<input type="file" id="uploadInput" />
<img id="imagePreview" style="width:300px;" class="normal" />

Related

Prevent form submission but reflecting it in URL

Working with vanilla JS is there a "way" where i could essentially event.preventDefault while reflecting the URL on the form. I want to give people the choice to copy and paste the link and share to their friends.
My javascript code is doing something like
searchKeywordForm.addEventListener('submit', async (event) => {
event.preventDefault();
//Clear all courseItems and start from scratch
courseItems = [];
courseContainerElement.innerHTML = "";
let searchInput = document.getElementById("keywords");
await fetchDataByKeywords(searchInput.value);
})
In so doing it's not reflected in the url that i can do file:///C:/Users/bobby/Desktop/twitdemy/index.html?keywords=cas
I have already did some checks for queryString so essentially it works.
Right now since there is event.preventDefault the url is basically static at file:///C:/Users/bobby/Desktop/twitdemy/index.html
You can use history.pushState() to modify the current url without reloading page
const searchKeywordForm = document.forms.keyform
searchKeywordForm.addEventListener('submit', (e) => {
e.preventDefault();
const searchInput = document.getElementById("keywords"),
newUrl = `${searchKeywordForm.action}?key=${searchInput.value}`;
history.pushState(null, null, newUrl)
// log current location to see changes
console.log(location.href)
})
<form id="keyform" action="/formsubmiturl">
<input id="keywords" value="foo" />
<button>Submit</button>
</form>

Fill the file details when dropped into input file

I have made a drag and drop file upload. Now when a file is dropped in the drop zone it should fill the data of the dropped file into <input type="file">. How to do it ?
HTML
:
<div id='slct'>
Select file <input type="file" id="filename"
onchange="readURL(this);" /> <input type="button" value="Upload"
onclick="sendFile()" /><br> Or
</div>
<button id='uploadDrp'>Upload</button>
<div class="drop">
<div id="filedrag">drop file here</div>
<img src="#" id="prof">
</div>
JavaScript :
obj.on("dragover", function(e) {
e.stopPropagation();
e.preventDefault();
$(this).css("border", "1px solid #00aaff");
});
obj.on("drop", function(e) {
e.stopPropagation();
e.preventDefault();
$(this).css("border", "1px solid #00aaff");
$("#slct").hide();
$("#uploadDrp").fadeIn(500);
var dt = e.originalEvent.dataTransfer;
file01 = dt;
var files = dt.files;
if (dt.files.length > 0) {
if (dt.files && dt.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
$('#prof').attr('src', e.target.result).width(200)
.height(200);
$('#prof').fadeIn();
};
reader.readAsDataURL(dt.files[0]);
}
}
});
History lession
It s like #adeneo said,
You can't set the value of a file input, due to security restrictions
But in some browser you can set the value to a empty string to clear the field.
In older (IE) browser you need to replace the DOM-node completely
However there is one way to change the input-file-value and that is with another instance of FileList
but you do not set the value, instead you set the input.files property: see jsfiddle demo here
I filled a bug report long ago to ask if we could get access to construct a new FileList
We had it globaly in window but there is no way we can use it...
var file1 = new File(['foo'], 'foo.txt')
var file2 = new File(['bar'], 'bar.txt')
new window.FileList([file1, file2]) // throws Illegal constructor
There response was that they are moving towards a normal array instead.
It s being descussed here to change it. But there is little to no progress in that field...
Solution
Unfortenly you can not change the value and sumbit the form, Instead you need to create a own FormData and post it using ajax
Then you can redirect to the target url...
// Make your own FormData
var fd = new FormData
// Add all drang'n'drop files
for (let file of dt.files)
fd.append('files', file)
// Add all input files
for (let file of input.files)
fd.append('files', file)
// upload it using xhr or the new fetch api
fetch(targetUrl, {method: 'post', body: fd}).then(redirect)
Code review
if (dt.files.length > 0) {
// it's unnecessary to have two if statement that checks the same thing
if (dt.files && dt.files[0]) {
// Using FileReader is unnecessary and also worse
// see this performance test: https://jsfiddle.net/fdzmd4mg/1
var reader = new FileReader();
reader.onload = function(e) {
$('#prof').attr('src', e.target.result).width(200).height(200);
$('#prof').fadeIn();
};
reader.readAsDataURL(dt.files[0]);
}
}
What i think you should do instead is something like this
if (dt.files && dt.files[0]) {
// store the file list somehere to upload them later
// window.files = Array.from(dt.files)
// window.files = [dt.files[0]]
let url = URL.createObjectURL(dt.files[0])
$('#prof').attr('src', url).width(200).height(200);
$('#prof').fadeIn();
}

multiple file input html not working

I have the following code for multiple file input
<form action="" enctype = "multipart/form-data" method="post" name="login">
<input type = "file" name = "photo[]" id = "files" multiple onchange = "handleFileSelect(this.files)"/><br/>
<div id="selectedFiles"></div>
<input type="submit" value="Sign In">
</form>
The javascript equivalent function is.
selDiv = document.querySelector("#selectedFiles");
function handleFileSelect(e) {
if(!this.files) return;
selDiv.innerHTML = "";
var files = e;
for(var i=0; i<files.length; i++) {
var f = files[i];
selDiv.innerHTML += f.name + "<br/>";
}
}
What I am getting is upon uploading the second file. The FileList gets overwritten and instead of having 2 files, second file is present in the FileList. Here FileList is passed by this.files.
Also upon passing to the server only second image is passed. I have googled throughly but could not find answer. I would appreciate if anyone could help.
...multiple file input ... The FileList gets overwritten...
Actually that's how the HTML file input with the multiple attribute works—the user must select all the files they want to upload at once, using shift or control click. If the user operates the same file input upload process a second time anything selected prior is discarded and only the most recent selections remain in the FileList.
But isn't there any way for the user upload file multiple times.
To let your site users use an HTML file input element multiple times and keep all the previous selections, you'll need to write to hidden form elements the file (base64 data) received each time the file element is used.
For example:
<form action="process.php" method="post" name="uploadform" enctype="multipart/form-data">
// other form elements if needed
<input type="submit">
</form>
<!-- outside the form, you don't want to upload this one -->
<input type="file" id="upfiles" name="upfiles">
<script>
document.getElementById('upfiles').addEventListener('change', handle_files, false);
function handle_files(evt) {
var ff = document.forms['uploadform'];
var files = evt.target.files;
for ( var i = 0, file; file = files[i]; i++ ) {
var reader = new FileReader();
reader.onload = (function(file) {
return function (ufile) {
var upp = document.createElement('input');
upp['type'] = 'hidden';
upp['name'] = +new Date + '_upfile_' + file.name.replace(/(\[|\]|&|~|!|\(|\)|#|\|\/)/ig, '');
upp.value = ufile.target.result;
ff.appendChild(upp);
}
}(file));
reader.readAsDataURL(file);
}
}
</script>
Next, you need to write a script to run on the server to process the hidden base64 fields. If using PHP you can:
<?php
$path = 'path/to/file/directory/';
// this is either:
// - the absolute path, which is from server root
// to the files directory, or
// - the relative path, which is from the directory
// the PHP script is in to the files directory
foreach ( $_POST as $key => $value ) { // loop over posted form vars
if ( strpos($key, '_upfile_') ) { // find the file upload vars
$value = str_replace(' ', '+', $value); // url encode
file_put_contents($path.$key, base64_decode($value));
// convert data to file in files directory with upload name ($key)
}
}
?>
I ran into the same problem. Thanks for the question and answer. I managed to add several files by adding to the DOM input type file and delegating the click to the detached element :
<form method="POST" enctype="multipart/form-data" action="/echo/html">
<button class="add">
Add File
</button>
<ul class="list">
</ul>
<button>
Send Form
</button>
</form>
With the javascript :
$('form button.add').click(function(e) {
e.preventDefault();
var nb_attachments = $('form input').length;
var $input = $('<input type="file" name=attachment-' + nb_attachments + '>');
$input.on('change', function(evt) {
var f = evt.target.files[0];
$('form').append($(this));
$('ul.list').append('<li class="item">'+f.name+'('+f.size+')</li>');
});
$input.hide();
$input.trigger('click');
});
It is working with Edge, Chrome 50 and firefox 45, but I don't know the compatibility with older versions or other browsers.
See the this fiddle.

JavaScript Query Json String from (api.census.gov)

I have an API which should return some text JSon String.
http://api.census.gov/data/2010/sf1?get=P0010001&for=county:013&in=state:08
I wan to use JavaScript to query this API and display in the HTML element. The code looks like this:
//html
<input type="submit" value="Get City" onclick=" getpop()">
//JS:
function getpop() {
var nereq2 = new XMLHttpRequest();
nereq2.open("GET", "http://api.census.gov/data/2010/sf1?get=P0010001&for=county:013&in=state:08", true);
nereq2.onreadystatechange = function () {
if (nereq2.readyState == 4) {
var temp3 = nereq.response; **//problem start at here, which always return empty*******
document.getElementById("fs").innerHTML = temp3;
};
};
nereq2.send();
}
When I click the link it returns the JSon properly, however when I use the code to query, it returns empty. I don't know whether it related to the browser setup or there are some other issues?
You have a typo. nereq.response should be nereq2.response.
Working JSFiddle - (using https here because JSFiddle requires that)

HTML input file selection event not firing upon selecting the same file

Is there any chance to detect every file selection the user made for an HTML input of type file element?
This was asked many times before, but the usually proposed onchange event doesn't fire if the user select the same file again.
Set the value of the input to null on each onclick event. This will reset the input's value and trigger the onchange event even if the same path is selected.
var input = document.getElementsByTagName('input')[0];
input.onclick = function () {
this.value = null;
};
input.onchange = function () {
console.log(this.value);
};
<input type="file" value="C:\fakepath">
Note: It's normal if your file is prefixed with 'C:\fakepath'. That's a security feature preventing JavaScript from knowing the file's absolute path. The browser still knows it internally.
Use onClick event to clear value of target input, each time user clicks on field. This ensures that the onChange event will be triggered for the same file as well. Worked for me :)
onInputClick = (event) => {
event.target.value = ''
}
<input type="file" onChange={onFileChanged} onClick={onInputClick} />
Using TypeScript
onInputClick = ( event: React.MouseEvent<HTMLInputElement, MouseEvent>) => {
const element = event.target as HTMLInputElement
element.value = ''
}
<form enctype='multipart/form-data'>
<input onchange="alert(this.value); this.value=null; return false;" type='file'>
<br>
<input type='submit' value='Upload'>
</form>
this.value=null; is only necessary for Chrome, Firefox will work fine just with return false;
Here is a FIDDLE
In this article, under the title "Using form input for selecting"
http://www.html5rocks.com/en/tutorials/file/dndfiles/
<input type="file" id="files" name="files[]" multiple />
<script>
function handleFileSelect(evt) {
var files = evt.target.files; // FileList object
// files is a FileList of File objects. List some properties.
var output = [];
for (var i = 0, f; f = files[i]; i++) {
// Code to execute for every file selected
}
// Code to execute after that
}
document.getElementById('files').addEventListener('change',
handleFileSelect,
false);
</script>
It adds an event listener to 'change', but I tested it and it triggers even if you choose the same file and not if you cancel.
handleChange({target}) {
const files = target.files
target.value = ''
}
<input #myInput type="file" id="imgFile" (click)="$event.target.value=null"
(change)="detectUploadedImage($event)" accept="image/*" />
Clearing the value of 0th index of input worked for me. Please try the below code, hope this will work (AngularJs).
scope.onClick = function() {
input[0].value = "";
input.click();
};
Usage of two way binding worked for me if you are working with Angular.
Here is my HMTL
<input type="file" #upload name="upload" [(ngModel)]="inputValue"(change)='fileEvent($event)'/>
and TS..
#ViewChild('upload') uploadBtn: HTMLElement;
fileEvent(e: any){
//file upload part...
this.inputValue = "";
}
The selected answer (using state to set input value null) gave me an error.
I use empty strings instead
const [fileValue, setFileValue] = React.useState("")
<input
onClick={() => {
setFileValue("");
}}
type="file"
value={fileValue}
onChange={handleAddFile}
/>
Do whatever you want to do after the file loads successfully.just after the completion of your file processing set the value of file control to blank string.so the .change() will always be called even the file name changes or not. like for example you can do this thing and worked for me like charm
$('#myFile').change(function () {
LoadFile("myFile");//function to do processing of file.
$('#myFile').val('');// set the value to empty of myfile control.
});

Categories

Resources