This question already has answers here:
Javascript - How to extract filename from a file input control
(15 answers)
Closed 2 years ago.
Trying to display the file names from a file input element. I am able to console log when I am inside the onchange function but not the addeventlistener. In the code below the console.log('Inside change eventlistener'); will not execute. I can I both log being inside the event listener and get the file names in order to display them? Here is the codepen of the code. Thank you.
html:
<label>Attachments</label>
<div>
<input type="file" class="form-control input-lg" name="attachments" id="attachments" multiple onchange="getFileData()">
</div>
js:
function getFileData() {
console.log('Inside getFileData()...')
var elem = document.getElementById('attachments');
console.log(elem);
elem.addEventListener('change', function(e) {
console.log('Inside change eventlistener');
console.log(e.target);
var fileName = e.target.files[0].name;
console.log(fileName);
});
};
UPDATE:
I am able to console the file names but still not able to display the names to the user. How do I show the names of the files within on the html page. elem.value = ... does not work.
Updated JS:
function getFileData() {
console.log('Inside getFileData()...')
var elem = document.getElementById('attachments');
var files = document.getElementById('attachments').files;
var names = '';
for (let i = 0; i < files.length; i++) {
console.log(files[i].name);
names += files[i].name;
}
console.log(names);
console.log(Object.keys(elem));
//elem.setAttribute('value', names);
};
You may try something like this
var elem = document.getElementById('attachments');
elem.addEventListener('change', getFileData);
function getFileData() {
const files = this.files;
const list = document.getElementById("result");
let child;
for ( let i = 0; i < files.length; i++) {
child = document.createElement("li")
child.textContent = files[i].name;
list.append(child);
}
}
<label>Attachments</label>
<div>
<input type="file" class="form-control input-lg" name="attachments" id="attachments" multiple>
</div>
<ul id="result"></ul>
Related
How to remove specific file from files selected with input type with multiple attribute?
<input type="file" (change)="onFileChange($event)" #fileInput multiple>
I want to delete one of the selected file.
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file
https://jsfiddle.net/Sagokharche/eL3eg6k4/
Do you need it to be impossible to choose? Then use HTML Input file accept property. accept="image/png" for instance.
Or you want it to filter from the input after the user selected it?
Then you should use a custom directive or check for the file types in the ts code upon upload.
EDIT
in that case, in your code:
onFileChange(event) {
const fileList = event.target.files;
console.log("User selected fileList:", fileList)
Array.from(fileList).filter(
item => {
console.log("file mime type:", item['type'])
})
const filesToUpload = Array.from(fileList).filter(
item => { return item['type'] != "application/zip" })
console.log("reduced list:", filesToUpload)
}
Working stackblitz example here.
You can access the inputs FileList-object in .ts side like this:
onFileChange(event) {
console.log(event.srcElement.files);
}
Edit:
If you are looking for a solution how to make dynamic form (add and delete inputs), then have a look at this answer and demo:
Angular 4 Form FormArray Add a Button to add or delete a form input row
In your hmtl code
<div class="row">
<div class="col-md-2 productAddfromImages" *ngFor='let url of imageurls; let i = index'>
<img class="img-fluid" [src]="url.base64String">
<a (click)="removeImage(i)" class="btn btn-xs btn-danger">Remove</a>
</div>
</div>
Remove function
removeImage(i) {
this.imageurls.splice(i, 1);
}
Add Function
onSelectFile(event) {
if (event.target.files && event.target.files[0]) {
var filesAmount = event.target.files.length;
for (let i = 0; i < filesAmount; i++) {
var reader = new FileReader();
reader.onload = (event: any) => {
this.imageurls.push({ base64String: event.target.result, });
}
reader.readAsDataURL(event.target.files[i]);
}
}
}
}
For more details:https://findandsolve.com/articles/how-to-upload-and-remove-multiple-image-using-anular-code-example
I have found a code on internet to upload multiple images. While you select the image, it will show the selected image just below as preview, now the problem is what if I selected the wrong image and I want to remove that particular image, also no more than 4 image should be allowed
hope you get what I want to say below is the code
<input type="file" multiple id="gallery-photo-add">
<div class="gallery"></div>
and jquery for the code is
$(function() {
// Multiple images preview in browser
var imagesPreview = function(input, placeToInsertImagePreview) {
if (input.files) {
var filesAmount = input.files.length;
for (i = 0; i < filesAmount; i++) {
var reader = new FileReader();
reader.onload = function(event) {
$($.parseHTML('<img>')).attr('src', event.target.result).appendTo(placeToInsertImagePreview);
}
reader.readAsDataURL(input.files[i]);
}
}
};
$('#gallery-photo-add').on('change', function() {
imagesPreview(this, 'div.gallery');
});
});
The file list of HTML5 file input is readonly. So it's not possible to remove a single file out from a multiple file selection.
It's perfectly fine to empty a file input by resetting the form. You just can't modify it. So if you use 4 seperate single file selections, it's a simple matter of clearing the one that's being removed by the user:
HTML:
<form>
<input type="file" name='images[]' class="gallery-photo-add" id='image1' />
<input type="file" name='images[]' class="gallery-photo-add" id='image2' />
<input type="file" name='images[]' class="gallery-photo-add" id='image3' />
<input type="file" name='images[]' class="gallery-photo-add" id='image4' />
</form>
<div class="gallery"></div>
JS:
$(function() {
// Multiple images preview in browser
var imagesPreview = function(placeToInsertImagePreview) {
// Empty preview so we can safely rebuild it
$(placeToInsertImagePreview).empty();
// Get all files
var elems = document.getElementsByClassName("gallery-photo-add");
// Loop through each file and append them to the preview if available
for (i = 0; i < elems.length; i++) {
if (elems[i].files.length != 0) {
var reader = new FileReader();
var id = $(elems[i]).attr('id');
reader.onload = (function(id) {
return function(e){
$($.parseHTML('<img>')).attr({
'src' : e.target.result,
'data-id' : id
}).appendTo(placeToInsertImagePreview);
}
})(id);
reader.readAsDataURL(elems[i].files[0]);
}
}
};
// Temporarely wrap a form element around the input to reset it
window.reset = function(e) {
e.wrap("<form>").closest('form').get(0).reset();
e.unwrap();
}
$('div.gallery').on('click', 'img', function() {
var id = $(this).attr("data-id");
reset($('#'+id));
$(this).remove();
});
$('.gallery-photo-add').on('change', function() {
imagesPreview('div.gallery');
});
});
You can test it here: https://jsfiddle.net/81nytqsc/2/
$('div.gallery').on('click','img',function(){
var files= $('#gallery-photo-add).get(0).files;
for(i=0;i<files.length;i++){
if(files[i]==$(this).attr('src')){
files= jQuery.grep(files, function(value) {
return value != files[i];
}
}
}
$(this).remove();
});
I have problem with uploading files in my existing form.
What I am looking for is script that will make possible to add multiple files (max 5) and you can add at once from one to five files. If you add one by one, I need it to add new, not replace the previous one.
I got form looking like this:
Name
LastName
Email
Phone number
Interests
Files
and filenames are created like this: name+lastname+phonenumber+filename
And I add entry to database with path of everyfile - this is done and I need only good drag and drop zone.
I need it to show added filename and make it possible to delete added file from queue.
But I don't want files to upload when I add them. I want it to upload when I submit my whole form so filename can be created and path to DB can be added.
Could anyone please provide me good script to that, or based on my scripts from two topics I mentioned before make it avaiable to do what I want?
I was able to add 5 files one by one and I described it here:
HTML Add multiple file to the input
Also I was able to add more at once what I described here:
https://stackoverflow.com/questions/30499388/dropzone-js-into-another-form
I think that this example help you.
This app allow drag and drop files to gray zone (1 or 5)
If you click on the file name, it removes file from the list.
function init() {
//get dragdrop element
var dd = document.getElementById("dragdrop");
//get files element
$files = document.getElementById("files");
dd.ondragover = stop;
dd.ondragleave = stop;
if ('FileReader' in window) {
document.ondrop = dragAccept;
}
//get form
var $form = document.querySelector("form");
//catch on submit
$form.onsubmit = function (e) {
stop(e);
var fd = new FormData();
//apend files to FormData
for (var i in files){
var file = files[i].file;
var filename = file.name;
var name = "file";
fd.append(name, file, filename);
};
//append inputs to FormData
var $inputs = $form.querySelectorAll("input");
for (var i = 0; i < $inputs.length; i++) {
var $input = $inputs[i];
fd.append($input.getAttribute("name"), $input.value);
}
//Send data
var xhr = new XMLHttpRequest();
xhr.open('POST', '/echo/html/', true);
xhr.send(fd)
}
}
function stop(e) {
e.stopPropagation();
e.preventDefault();
}
function dragAccept(e) {
stop(e);
if (e.dataTransfer.files.length > 0)
for (var i = 0; i < e.dataTransfer.files.length; i++) {
addFile(e.dataTransfer.files[i]);
}
}
//file list store
var files = {};
// html element of file list
var $files = null;
//add file to file list
function addFile(file) {
//add files with diferent name, max files count 5
if (!(file.name in files) && Object.keys(files).length < 5) {
var div = createFile(file.name);
$files.appendChild(div);
files[file.name] = {
file: file,
element: div
}
}
}
//create html element with file name
function createFile(name) {
var div = document.createElement("div");
div.innerText = name;
var input = document.createElement("input")
//remove on click
div.addEventListener("click", function () {
$files.removeChild(this);
delete files[name];
})
return div;
}
window.addEventListener("load", init);
<form method="post" enctype="multipart/form-data" action="">
<label>Name<input name="name" /></label>
<label>Last name<input name="lastName" /></label>
<label>Email<input name="email" /></label>
<div id="dragdrop" style="width: 300px; height: 300px; background-color:lightgray">Drag drop zone</div>
<div id="files"></div>
<button type="submit">Send</button>
</form>
I have done this in jQuery, to get filename from input file tag, With jQuery it works perfectly.
//jQuery('input[type=file]').on('change', prepareUpload);
document.getElementsByTagName('input[type=file]').addEventListener('change',prepareUpload1,true);
/*
//this works in jQuery
function prepareUpload(event)
{
var files = event.target.files;
var fileName = files [0].name
alert(fileName);
}
*/
/****Check it here ****/
// it does not work in javascript
function prepareUpload1(event)
{
var files = event.target.files;
var fileName = files [0].name
alert("fileName 2 : "+fileName);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="file" />
But I found Event.target does not work in IE, I tried to change it to java script addeventlistener, it did not work.
It throws error
Uncaught ReferenceError: input is not defined
It is working in jQuery but it is not working in JS, Due to IE issue I need to change it to JS.
Can some one help
I found the problem to be in getElementsByTagName method, you use this when you have a group of elements with the same tag name.
Try this code below, it works
//HTML
<input id="inp" type="file" />
// JavaScript
document.getElementById('inp').addEventListener('change',prepareUpload,false);
function prepareUpload(event)
{
var files = event.target.files;
var fileName = files[0].name;
alert(fileName);
}
Below is the code if you want to do it for more than one element
<body>
<input type="file" class="input"/>
<input type="file" class="input"/>
<input type="file" class="input"/>
<input type="file" class="input"/>
<script>
var inputArray = document.getElementsByClassName('input');
for(var i = 0; i < inputArray.length; i++){
inputArray[i].addEventListener('change',prepareUpload,false);
};
function prepareUpload(event)
{
var files = event.target.files;
var fileName = files[0].name;
alert(fileName);
}
</script>
</body>
This will work
var fileName = $("input[type='file']").val().split('/').pop().split('\\').pop();
The code above is correct for all but IE simply because IE doesn't like event.target - you need event.srcElement: https://developer.mozilla.org/en-US/docs/Web/API/Event/srcElement
So something like this should sort that out:
var files;
if (window.navigator.userAgent.indexOf("MSIE ") > 0) ?
files = event.srcElement.files :
files = event.target.files;
I couldn't make that work in the "Run Snippet" thing SO has, though, so here's how you can just get it using another button:
document.getElementById('myBtn').addEventListener('click', function() {
doUpload();
});
function doUpload()
{
var myFile = myInput.files[0];
// can also use var myFile = document.querySelector('input').files[0];
var fileName = myFile.name;
alert(fileName);
}
<input id="myInput" type="file" />
<button id="myBtn">Try Me</button>
I have a tabbed html form. Upon navigating from one tab to the other, the current tab's data is persisted (on the DB) even if there is no change to the data.
I would like to make the persistence call only if the form is edited. The form can contain any kind of control. Dirtying the form need not be by typing some text but choosing a date in a calendar control would also qualify.
One way to achieve this would be to display the form in read-only mode by default and have an 'Edit' button and if the user clicks the edit button then the call to DB is made (once again, irrespective of whether data is modified. This is a better improvement to what is currently existing).
I would like to know how to write a generic javascript function that would check if any of the controls value has been modified ?
In pure javascript, this would not be an easy task, but jQuery makes it very easy to do:
$("#myform :input").change(function() {
$("#myform").data("changed",true);
});
Then before saving, you can check if it was changed:
if ($("#myform").data("changed")) {
// submit the form
}
In the example above, the form has an id equal to "myform".
If you need this in many forms, you can easily turn it into a plugin:
$.fn.extend({
trackChanges: function() {
$(":input",this).change(function() {
$(this.form).data("changed", true);
});
}
,
isChanged: function() {
return this.data("changed");
}
});
Then you can simply say:
$("#myform").trackChanges();
and check if a form has changed:
if ($("#myform").isChanged()) {
// ...
}
I am not sure if I get your question right, but what about addEventListener? If you don't care too much about IE8 support this should be fine. The following code is working for me:
var form = document.getElementById("myForm");
form.addEventListener("input", function () {
console.log("Form has changed!");
});
In case JQuery is out of the question. A quick search on Google found Javascript implementations of MD5 and SHA1 hash algorithms. If you wanted, you could concatenate all form inputs and hash them, then store that value in memory. When the user is done. Concatenate all the values and hash again. Compare the 2 hashes. If they are the same, the user did not change any form fields. If they are different, something has been edited, and you need to call your persistence code.
Another way to achieve this is serialize the form:
$(function() {
var $form = $('form');
var initialState = $form.serialize();
$form.submit(function (e) {
if (initialState === $form.serialize()) {
console.log('Form is unchanged!');
} else {
console.log('Form has changed!');
}
e.preventDefault();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
Field 1: <input type="text" name="field_1" value="My value 1"> <br>
Field 2: <input type="text" name="field_2" value="My value 2"> <br>
Check: <input type="checkbox" name="field_3" value="1"><br>
<input type="submit">
</form>
Form changes can easily be detected in native JavaScript without jQuery:
function initChangeDetection(form) {
Array.from(form).forEach(el => el.dataset.origValue = el.value);
}
function formHasChanges(form) {
return Array.from(form).some(el => 'origValue' in el.dataset && el.dataset.origValue !== el.value);
}
initChangeDetection() can safely be called multiple times throughout your page's lifecycle: See Test on JSBin
For older browsers that don't support newer arrow/array functions:
function initChangeDetection(form) {
for (var i=0; i<form.length; i++) {
var el = form[i];
el.dataset.origValue = el.value;
}
}
function formHasChanges(form) {
for (var i=0; i<form.length; i++) {
var el = form[i];
if ('origValue' in el.dataset && el.dataset.origValue !== el.value) {
return true;
}
}
return false;
}
Here's how I did it (without using jQuery).
In my case, I wanted one particular form element not to be counted, because it was the element that triggered the check and so will always have changed. The exceptional element is named 'reporting_period' and is hard-coded in the function 'hasFormChanged()'.
To test, make an element call the function "changeReportingPeriod()", which you'll probably want to name something else.
IMPORTANT: You must call setInitialValues() when the values have been set to their original values (typically at page load, but not in my case).
NOTE: I do not claim that this is an elegant solution, in fact I don't believe in elegant JavaScript solutions. My personal emphasis in JavaScript is on readability, not structural elegance (as if that were possible in JavaScript). I do not concern myself with file size at all when writing JavaScript because that's what gzip is for, and trying to write more compact JavaScript code invariably leads to intolerable problems with maintenance. I offer no apologies, express no remorse and refuse to debate it. It's JavaScript. Sorry, I had to make this clear in order to convince myself that I should bother posting. Be happy! :)
var initial_values = new Array();
// Gets all form elements from the entire document.
function getAllFormElements() {
// Return variable.
var all_form_elements = Array();
// The form.
var form_activity_report = document.getElementById('form_activity_report');
// Different types of form elements.
var inputs = form_activity_report.getElementsByTagName('input');
var textareas = form_activity_report.getElementsByTagName('textarea');
var selects = form_activity_report.getElementsByTagName('select');
// We do it this way because we want to return an Array, not a NodeList.
var i;
for (i = 0; i < inputs.length; i++) {
all_form_elements.push(inputs[i]);
}
for (i = 0; i < textareas.length; i++) {
all_form_elements.push(textareas[i]);
}
for (i = 0; i < selects.length; i++) {
all_form_elements.push(selects[i]);
}
return all_form_elements;
}
// Sets the initial values of every form element.
function setInitialFormValues() {
var inputs = getAllFormElements();
for (var i = 0; i < inputs.length; i++) {
initial_values.push(inputs[i].value);
}
}
function hasFormChanged() {
var has_changed = false;
var elements = getAllFormElements();
for (var i = 0; i < elements.length; i++) {
if (elements[i].id != 'reporting_period' && elements[i].value != initial_values[i]) {
has_changed = true;
break;
}
}
return has_changed;
}
function changeReportingPeriod() {
alert(hasFormChanged());
}
Here's a polyfill method demo in native JavaScript that uses the FormData() API to detect created, updated, and deleted form entries. You can check if anything was changed using HTMLFormElement#isChanged and get an object containing the differences from a reset form using HTMLFormElement#changes (assuming they're not masked by an input name):
Object.defineProperties(HTMLFormElement.prototype, {
isChanged: {
configurable: true,
get: function isChanged () {
'use strict'
var thisData = new FormData(this)
var that = this.cloneNode(true)
// avoid masking: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/reset
HTMLFormElement.prototype.reset.call(that)
var thatData = new FormData(that)
const theseKeys = Array.from(thisData.keys())
const thoseKeys = Array.from(thatData.keys())
if (theseKeys.length !== thoseKeys.length) {
return true
}
const allKeys = new Set(theseKeys.concat(thoseKeys))
function unequal (value, index) {
return value !== this[index]
}
for (const key of theseKeys) {
const theseValues = thisData.getAll(key)
const thoseValues = thatData.getAll(key)
if (theseValues.length !== thoseValues.length) {
return true
}
if (theseValues.some(unequal, thoseValues)) {
return true
}
}
return false
}
},
changes: {
configurable: true,
get: function changes () {
'use strict'
var thisData = new FormData(this)
var that = this.cloneNode(true)
// avoid masking: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/reset
HTMLFormElement.prototype.reset.call(that)
var thatData = new FormData(that)
const theseKeys = Array.from(thisData.keys())
const thoseKeys = Array.from(thatData.keys())
const created = new FormData()
const deleted = new FormData()
const updated = new FormData()
const allKeys = new Set(theseKeys.concat(thoseKeys))
function unequal (value, index) {
return value !== this[index]
}
for (const key of allKeys) {
const theseValues = thisData.getAll(key)
const thoseValues = thatData.getAll(key)
const createdValues = theseValues.slice(thoseValues.length)
const deletedValues = thoseValues.slice(theseValues.length)
const minLength = Math.min(theseValues.length, thoseValues.length)
const updatedValues = theseValues.slice(0, minLength).filter(unequal, thoseValues)
function append (value) {
this.append(key, value)
}
createdValues.forEach(append, created)
deletedValues.forEach(append, deleted)
updatedValues.forEach(append, updated)
}
return {
created: Array.from(created),
deleted: Array.from(deleted),
updated: Array.from(updated)
}
}
}
})
document.querySelector('[value="Check"]').addEventListener('click', function () {
if (this.form.isChanged) {
console.log(this.form.changes)
} else {
console.log('unchanged')
}
})
<form>
<div>
<label for="name">Text Input:</label>
<input type="text" name="name" id="name" value="" tabindex="1" />
</div>
<div>
<h4>Radio Button Choice</h4>
<label for="radio-choice-1">Choice 1</label>
<input type="radio" name="radio-choice-1" id="radio-choice-1" tabindex="2" value="choice-1" />
<label for="radio-choice-2">Choice 2</label>
<input type="radio" name="radio-choice-2" id="radio-choice-2" tabindex="3" value="choice-2" />
</div>
<div>
<label for="select-choice">Select Dropdown Choice:</label>
<select name="select-choice" id="select-choice">
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div>
<label for="textarea">Textarea:</label>
<textarea cols="40" rows="8" name="textarea" id="textarea"></textarea>
</div>
<div>
<label for="checkbox">Checkbox:</label>
<input type="checkbox" name="checkbox" id="checkbox" />
</div>
<div>
<input type="button" value="Check" />
</div>
</form>
I really like the contribution from Teekin above, and have implemented it.
However, I have expanded it to allow for checkboxes too using code like this:
// Gets all form elements from the entire document.
function getAllFormElements() {
// Return variable.
var all_form_elements = Array();
// The form.
var Form = document.getElementById('frmCompDetls');
// Different types of form elements.
var inputs = Form.getElementsByTagName('input');
var textareas = Form.getElementsByTagName('textarea');
var selects = Form.getElementsByTagName('select');
var checkboxes = Form.getElementsByTagName('CheckBox');
// We do it this way because we want to return an Array, not a NodeList.
var i;
for (i = 0; i < inputs.length; i++) {
all_form_elements.push(inputs[i]);
}
for (i = 0; i < textareas.length; i++) {
all_form_elements.push(textareas[i]);
}
for (i = 0; i < selects.length; i++) {
all_form_elements.push(selects[i]);
}
for (i = 0; i < checkboxes.length; i++) {
all_form_elements.push(checkboxes[i]);
}
return all_form_elements;
}
// Sets the initial values of every form element.
function setInitialFormValues() {
var inputs = getAllFormElements();
for (var i = 0; i < inputs.length; i++) {
if(inputs[i].type != "checkbox"){
initial_values.push(inputs[i].value);
}
else
{
initial_values.push(inputs[i].checked);
}
}
}
function hasFormChanged() {
var has_changed = false;
var elements = getAllFormElements();
var diffstring = ""
for (var i = 0; i < elements.length; i++) {
if (elements[i].type != "checkbox"){
if (elements[i].value != initial_values[i]) {
has_changed = true;
//diffstring = diffstring + elements[i].value+" Was "+initial_values[i]+"\n";
break;
}
}
else
{
if (elements[i].checked != initial_values[i]) {
has_changed = true;
//diffstring = diffstring + elements[i].value+" Was "+initial_values[i]+"\n";
break;
}
}
}
//alert(diffstring);
return has_changed;
}
The diffstring is just a debugging tool