I have multiple file input and I am returning names of selected items, I want to add remove option to my list so for instance when user selects 2 files then can remove any of them before uploading files.
Code
<!-- HTML -->
<input type="file" name="file" placeholder="Choose File" id="file" multiple>
<!-- showing selected files names -->
<div class="row">
<div class="col-md-12 filenames"></div>
</div>
<!-- SCRIPT -->
$(document).ready(function (e) {
document.getElementById('file').onchange = function () {
var row = 0;
if (this.files.length > 0) {
// THE TOTAL FILE COUNT.
$('.filenames').append('Total Selected Files: <b>' + this.files.length + '</b></br >');
// RUN A LOOP TO CHECK EACH SELECTED FILE.
for (var i = 0; i <= this.files.length - 1; i++) {
var fname = this.files.item(i).name; // THE NAME OF THE FILE.
var fsize = this.files.item(i).size; // THE SIZE OF THE FILE.
// SHOW THE EXTRACTED DETAILS OF THE FILE.
$('.filenames').append(++row + "- " + fname + ' (<b>' + fsize + '</b> bytes) <hr/>');
}
}
};
});
Current result
Any suggestions?
Seems like there is no method provided by the File API to remove the file from the FileList, but you could create an regular array from the FileList object and then just use the splice method and delete the file by the index.
let files = []
$("#file").on('change', function() {
files = [...files, ...this.files]
renderFiles(files)
})
$("#submit").on('click', function() {
console.log(files)
})
function renderFiles(files) {
let row = 0;
$('.filenames').html('')
if (files.length) {
$('.filenames').append(`Total Selected Files: <b>${files.length}</b></br >`);
files.forEach(({ name, size }, index) => {
const fileEl = $('<div class="file-item">')
const text = $('<span>', {
html: `${++row}- ${name} (<b>${size}</b> bytes)`
})
const btn = $('<button>', {
text: 'X'
})
btn.on('click', function() {
files.splice(index, 1)
renderFiles(files)
})
fileEl.append(text)
fileEl.append(btn)
$('.filenames').append(fileEl);
$('.filenames').append('<hr />')
})
}
}
.file-item {
display: flex;
align-items: center;
justify-content: space-between;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- HTML -->
<input type="file" name="file" placeholder="Choose File" id="file" multiple>
<!-- showing selected files names -->
<div class="row">
<div class="col-md-12 filenames"></div>
</div>
<div class="row">
<button id="submit">Submit</button>
</div>
Related
My goal is to get a way to upload multiple images and also set in which order they should be displayed later on (it's for an ecommerce website). I have an idea which seems to work. But I would like to know if there is a better way of doing this. Here is my code. Let's assume the number of images is limited to 3.
One input for multiple images.
Preview images and make them sortable.
Store the order in hidden inputs.
Store the images in the filesystem.
Add the path and order index of every image to the database.
HTML
<!-- One input for all images -->
<input type="file" name="images[]" onchange="previewImages(this)" multiple>
<!-- This <div> will be made sortable with SortableJS -->
<div id="preview-parent">
<div class="preview">
<!--
Hidden input to save the order of images.
The idea is to have images_order[name_of_image] = index.
name_of_image and index will be set with JavaScript
-->
<input class="order-input" type="hidden" name="images_order[]" value="0">
<!-- <img> is for preview -->
<img class="preview-image" src="" alt="Image1">
</div>
<div class="preview">
<input class="order-input" type="hidden" name="images_order[]" value="1">
<img class="preview-image" src="" alt="Image2">
</div>
<div class="preview">
<input class="order-input" type="hidden" name="images_order[]" value="2">
<img class="preview-image" src="" alt="Image3">
</div>
</div>
JavaScript
function previewImages(input) {
// First I take the images
var file = input.files
// Then I go through each of them. This code is based on the explanation
// from https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL
for (var i = 0; i < file.length; i++) {
let preview = document.querySelectorAll('.preview-image')[i]
let reader = new FileReader()
reader.onloadend = function () {
preview.src = reader.result
}
if (file[i]) {
reader.readAsDataURL(file[i])
// In addition to previewing images I take their names
// and put them into my hidden inputs
let order_inputs = document.querySelectorAll('.order-input')
order_inputs[i].name = 'images_order[' + file[i].name +']'
} else {
preview.src = ""
}
}
}
// I make the images sortable by means of SortableJS
var el = document.getElementById('preview-parent')
new Sortable(el, {
animation: 150,
// This function updates the values of my hidden inputs
// every time a change is made
onEnd: function (event) {
let order_inputs = document.querySelectorAll('.order-input')
for (var i = 0; i < order_inputs.length; i++) {
order_inputs[i].value = [i]
}
}
})
function previewImages(input) {
var file = input.files
for (var i = 0; i < file.length; i++) {
let preview = document.querySelectorAll('.preview-image')[i]
let reader = new FileReader()
reader.onloadend = function () {
preview.src = reader.result
}
if (file[i]) {
reader.readAsDataURL(file[i])
let order_inputs = document.querySelectorAll('.order-input')
order_inputs[i].name = 'images_order[' + file[i].name +']'
} else {
preview.src = ""
}
}
}
var el = document.getElementById('preview-parent')
new Sortable(el, {
animation: 150,
onEnd: function (event) {
let order_inputs = document.querySelectorAll('.order-input')
for (var i = 0; i < order_inputs.length; i++) {
order_inputs[i].value = [i]
}
}
})
#preview-parent {
display: flex;
gap: 1rem;
margin: 1rem;
}
.preview {
height: 100px;
width: 100px;
padding: 1rem;
border: 1px solid grey;
}
.preview img {
max-height: 100%;
max-width: 100%;
}
<script src="https://cdn.jsdelivr.net/npm/sortablejs#latest/Sortable.min.js"></script>
<input type="file" name="images[]" onchange="previewImages(this)" multiple>
<div id="preview-parent">
<div class="preview">
<input class="order-input" type="hidden" name="images_order[]" value="0">
<img class="preview-image" src="" alt="Image1">
</div>
<div class="preview">
<input class="order-input" type="hidden" name="images_order[]" value="1">
<img class="preview-image" src="" alt="Image2">
</div>
<div class="preview">
<input class="order-input" type="hidden" name="images_order[]" value="2">
<img class="preview-image" src="" alt="Image3">
</div>
</div>
I haven't figured out yet how to limit the number of submitted images. But I saw a number of discussions about that, so I hope it will not be a problem.
PHP. The next step is done by means of PHP (CodeIgniter 4). I take the images, store them in my filesystem. Also I add the path to every image and its order index (taken from the hidden input) to the database. Later when a user will open certain product, the data will be taken from the database and ordered by order index. So basically my controller has this:
// I inserted the product before and can get its id
$product_id = $this->products->insertID();
// This line is just for reference, I actually create $input earlier
$input = $this->request->getPost();
// Here I take all the images as suggested in CodeIgniter docs
if($imagefile = $this->request->getFiles())
{
foreach($imagefile['images'] as $img)
{
if ($img->isValid() && ! $img->hasMoved())
{
// Store each image
$name = $img->getName();
$img->move('assets/images/'.$product_id, $name);
// Add info about the image to the database
$data = [
'product_id' => $product_id,
'path' => base_url('assets/images/'.$product_id.'/'.$name),
'order_index' => $input['images_order'][$name],
];
$this->imagesModel->insert($data);
}
}
}
It would be perfect if I could upload multiple images at once and then not only reorder them but also be able to replace one of the images. If someone could share any ideas, I will appreciate it very much!
After long time I have returned to this project and made further research. So I would like to share my solution.
So I have decided that a convenient option will be to have only one input for multiple images. The user clicks it and chooses the needed images. If he needs to add more images after this, he clicks the same input again and the new images are added to the list. All images immediately appear as previews with the "delete" button. So if the user needs to replace one image, he can delete it, upload a new image and move it to the needed place.
The PHP code from my post does not require any changes. The work is done in Javascript. There are lots of lines of code, but a big part of them is simply for dynamic generating of previews. Please see the snippet.
// DataTransfer allows updating files in input
var dataTransfer = new DataTransfer()
const form = document.querySelector('#form')
const input = document.querySelector('#input')
input.addEventListener('change', () => {
let files = input.files
for (let i = 0; i < files.length; i++) {
// A new upload must not replace images but be added
dataTransfer.items.add(files[i])
// Generate previews using FileReader
let reader, preview, previewImage
reader = new FileReader()
preview = document.createElement('div')
previewImage = document.createElement('img')
deleteButton = document.createElement('button')
orderInput = document.createElement('input')
preview.classList.add('preview')
document.querySelector('#preview-parent').appendChild(preview)
deleteButton.setAttribute('data-index', i)
deleteButton.setAttribute('onclick', 'deleteImage(this)')
deleteButton.innerText = 'Delete'
orderInput.type = 'hidden'
orderInput.name = 'images_order[' + files[i].name + ']'
preview.appendChild(previewImage)
preview.appendChild(deleteButton)
preview.appendChild(orderInput)
reader.readAsDataURL(files[i])
reader.onloadend = () => {
previewImage.src = reader.result
}
}
// Update order values for all images
updateOrder()
// Finally update input files that will be sumbitted
input.files = dataTransfer.files
})
const updateOrder = () => {
let orderInputs = document.querySelectorAll('input[name^="images_order"]')
let deleteButtons = document.querySelectorAll('button[data-index]')
for (let i = 0; i < orderInputs.length; i++) {
orderInputs[i].value = [i]
deleteButtons[i].dataset.index = [i]
// Just to show that order is always correct I add index here
deleteButtons[i].innerText = 'Delete (index ' + i + ')'
}
}
const deleteImage = (item) => {
// Remove image from DataTransfer and update input
dataTransfer.items.remove(item.dataset.index)
input.files = dataTransfer.files
// Delete element from DOM and update order
item.parentNode.remove()
updateOrder()
}
// I make the images sortable by means of SortableJS
const el = document.getElementById('preview-parent')
new Sortable(el, {
animation: 150,
// Update order values every time a change is made
onEnd: (event) => {
updateOrder()
}
})
#preview-parent {
display: flex;
}
.preview {
display: flex;
flex-direction: column;
margin: 1rem;
}
img {
width: 100px;
height: 100px;
object-fit: cover;
}
<script src="https://cdn.jsdelivr.net/npm/sortablejs#latest/Sortable.min.js"></script>
<form method="post" enctype="multipart/form-data" id="form">
<input type="file" name="images[]" id="input" multiple>
<button type="submit">Save</button>
</form>
<!-- This <div> will be made sortable with SortableJS -->
<div id="preview-parent">
<!-- After upload Javascript will generate previews with this pattern
<div class="preview">
<img src="...">
<button data-index=0>Delete</button>
<input type="hidden" name="images_order['name']" value=0>
</div>
-->
</div>
Currently, I'm developing a drag and drop feature. The problem is that I can't figure out how to get multiple files from user separately. Let's say that we have a drop zone container and when user drops there images, it assigns them to <input type="file">. Let's say, a user drops here an image and then decides to drop another image and we have to somehow add this second image to the input. I tried finding solution in the Internet(of course :)) but found nothing that solves this problem.
Here is my HTML:
<form action="" method="POST" enctype="multipart/form-data">
<div class="drop_zone">
<span class="drop_zone__prompt">Drop your files here</span>
<input required name="images" type="file" multiple class="drop_zone__input">
</div>
<input type="submit" value="Отправить">
</form>
JavaScript:
document.querySelectorAll('.drop_zone__input').forEach(InputElement => {
const dropZoneElement = InputElement.closest('.drop_zone');
dropZoneElement.addEventListener('drop', e => {
e.preventDefault();
if (e.dataTransfer.files.length){
InputElement.files = e.dataTransfer.files;
}
});
I tried this:
dropZoneElement.addEventListener('drop', e => {
e.preventDefault();
if (e.dataTransfer.files.length){
myfiles = e.dataTransfer.add(InputElement.files);
InputElement.files = myfiles;
}
});
But it returns error saying that 'e.dataTransfer.add is not a function'
Why I tried this:
I found add() method here
And this article says:
The DataTransferItemList object is a list of DataTransferItem objects representing items being dragged. During a drag operation, each DragEvent has a dataTransfer property and that property is a DataTransferItemList.
Actually, there is a way to do that. It's far from straightforward, but it does work.
The only way to create a FileList object is to create a custom DataTransfer object. You can add files to it using dataTransfer.items.add(), and obtain the corresponding FileList through dataTransfer.files.
So, create a new DataTransfer object every time you want to add files, add the existing and the new files to it, and assign its FileList to the files property of the input element.
Note: You can't use the drop event's DataTransfer object for this, because it's read-only.
document.querySelectorAll('.drop_zone__input').forEach(InputElement => {
const dropZoneElement = InputElement.closest('.drop_zone');
dropZoneElement.addEventListener('dragover', e => {
e.preventDefault()
});
dropZoneElement.addEventListener('drop', e => {
e.preventDefault();
//Create a new DataTransfer object
const dataTransfer = new DataTransfer
//Add new files from the event's DataTransfer
for(let i = 0; i < e.dataTransfer.files.length; i++)
dataTransfer.items.add(e.dataTransfer.files[i])
//Add existing files from the input element
for(let i = 0; i < InputElement.files.length; i++)
dataTransfer.items.add(InputElement.files[i])
//Assign the files to the input element
InputElement.files = dataTransfer.files
});
})
.drop_zone{
height: 200px;
width: 200px;
border: solid black 1px;
}
<form action="" method="POST" enctype="multipart/form-data">
<div class="drop_zone">
<span class="drop_zone__prompt">Drop your files here</span>
<input required name="images" type="file" multiple class="drop_zone__input">
</div>
<input type="submit" value="Отправить">
</form>
You can also reuse the same DataTransfer object, so you don't have to re-add the existing files.
However, in this case, you also have to handle input events on the input element.
document.querySelectorAll('.drop_zone__input').forEach(InputElement => {
const dropZoneElement = InputElement.closest('.drop_zone');
const dataTransfer = new DataTransfer
dropZoneElement.addEventListener('dragover', e => {
e.preventDefault()
});
dropZoneElement.addEventListener('drop', e => {
e.preventDefault();
//Add new files from the event's DataTransfer
for(let i = 0; i < e.dataTransfer.files.length; i++)
dataTransfer.items.add(e.dataTransfer.files[i])
//Assign the files to the input element
InputElement.files = dataTransfer.files
});
InputElement.addEventListener('input', e => {
dataTransfer.items.clear()
for(let i = 0; i < InputElement.files.length; i++)
dataTransfer.items.add(InputElement.files[i])
})
})
.drop_zone{
height: 200px;
width: 200px;
border: solid black 1px;
}
<form action="" method="POST" enctype="multipart/form-data">
<div class="drop_zone">
<span class="drop_zone__prompt">Drop your files here</span>
<input required name="images" type="file" multiple class="drop_zone__input">
</div>
<input type="submit" value="Отправить">
</form>
Or, if you want to add the files when interacting with the file input instead of replacing them, you can do this:
document.querySelectorAll('.drop_zone__input').forEach(InputElement => {
const dropZoneElement = InputElement.closest('.drop_zone');
const dataTransfer = new DataTransfer
dropZoneElement.addEventListener('dragover', e => {
e.preventDefault()
});
dropZoneElement.addEventListener('drop', e => {
e.preventDefault();
//Add new files from the event's DataTransfer
for(let i = 0; i < e.dataTransfer.files.length; i++)
dataTransfer.items.add(e.dataTransfer.files[i])
//Assign the files to the input element
InputElement.files = dataTransfer.files
});
InputElement.addEventListener('input', e => {
e.preventDefault()
for(let i = 0; i < InputElement.files.length; i++)
dataTransfer.items.add(InputElement.files[i])
InputElement.files = dataTransfer.files
})
})
.drop_zone{
height: 200px;
width: 200px;
border: solid black 1px;
}
<form action="" method="POST" enctype="multipart/form-data">
<div class="drop_zone">
<span class="drop_zone__prompt">Drop your files here</span>
<input required name="images" type="file" multiple class="drop_zone__input">
</div>
<input type="submit" value="Отправить">
</form>
You can remove files from the DataTransfer object using dataTransfer.items.remove():
document.querySelectorAll('.drop_zone__input').forEach(InputElement => {
const dropZoneElement = InputElement.closest('.drop_zone');
const removeFirstElement = dropZoneElement.querySelector('.drop_zone__remove_first')
const dataTransfer = new DataTransfer
dropZoneElement.addEventListener('dragover', e => {
e.preventDefault()
});
dropZoneElement.addEventListener('drop', e => {
e.preventDefault();
//Add new files from the event's DataTransfer
for(let i = 0; i < e.dataTransfer.files.length; i++)
dataTransfer.items.add(e.dataTransfer.files[i])
//Assign the files to the input element
InputElement.files = dataTransfer.files
});
InputElement.addEventListener('input', e => {
e.preventDefault()
for(let i = 0; i < InputElement.files.length; i++)
dataTransfer.items.add(InputElement.files[i])
InputElement.files = dataTransfer.files
})
removeFirstElement.addEventListener('click', () => {
dataTransfer.items.remove(0)
InputElement.files = dataTransfer.files
})
})
.drop_zone{
height: 200px;
width: 200px;
border: solid black 1px;
}
<form action="" method="POST" enctype="multipart/form-data">
<div class="drop_zone">
<span class="drop_zone__prompt">Drop your files here</span>
<input required name="images" type="file" multiple class="drop_zone__input">
<input type="button" class="drop_zone__remove_first" value="Remove first file">
</div>
<input type="submit" value="Отправить">
</form>
You can't add to the files to the input's list of files, although apparently you can replace that list as described by FZs, which largely comes to the same thing.
Another way to deal with this is to make the original input hidden via CSS and add a new input where it used to be, so it can receive new files. You can make the UI clean by listing all of the files you're going to upload separately from the input.
How you deal with on submission depends on how you're handling submission.
If you're doing a standard HTTP form submission, ensure that your server side script handles all of the files regardless of which input they came from (it will receive more than one).
If you're submitting via ajax, you can use a FormData object and append each file to it, then submit that.
Here's a quick and dirty example maintaining the files in a FormData object:
let nextFileNum = 1;
const formData = new FormData();
const fileList = document.getElementById("file-list");
document.getElementById("inputs").addEventListener("input", function() {
let input = event.target.closest("input[type=file]");
if (!input) {
return;
}
for (const file of input.files) {
const fileId = `file${nextFileNum++}`;
formData.append(fileId, file, file.name);
debugShowCurrentFiles("added");
let div = document.createElement("div");
// This is a Q&D sketch, needs a11y
div.innerHTML = "<span tabindex class=delete>[X]</span><span class=filename></span>";
div.querySelector(".filename").textContent = file.name;
div.querySelector(".delete").addEventListener("click", function() {
formData.delete(fileId);
debugShowCurrentFiles("deleted");
div.remove();
div = null;
});
fileList.appendChild(div);
}
this.removeChild(input);
this.insertAdjacentHTML("beforeend", input.outerHTML);
input = null;
});
function debugShowCurrentFiles(action) {
const contents = [...formData.entries()];
console.log(`--- ${action}, updated formData contents (${contents.length}):`);
for (const [key, value] of contents) {
console.log(`${key}: ${value.name}`);
}
}
#file-list .delete {
margin-right: 2em;
cursor: pointer;
}
<div id="inputs">
<input type="file" multiple>
</div>
<div id="file-list"></div>
You can do this with FileList, heres an article about it.
Also added code snippet which outputs file name and type after you submit the form just for visualization.
let form = document.getElementById('file_drop_form');
function getFiles(event) {
event.preventDefault();
let files = document.getElementById('file').files;
for(let i = 0; i < files.length; i++) {
document.write(`Title: ${files[i].name}; Type: ${files[i].type} <br>`);
}
}
form.addEventListener('submit', getFiles);
<form id="file_drop_form" method="post" enctype="multipart/form-data">
<div>
<label for="file">Drop your files here</label>
<input type="file" id="file" name="file" required multiple>
</div>
<input type="submit" value="Submit">
</form>
I asked a question earlier with answers which didn't help, I still haven't been able to figure out where my issue is. Originally I thought it was because I had two IDs named the same but this was not the issue.. The form submits and there are no errors but it does not update the values in localStorage?
Edit: After changing const idx to const i the value at position [2] (or final value) would update for every booking (regardless of index). I thought of maybe changing the i value to below but it gives error i is defined before it is initialised?
bookings.findIndex(booking => bookings[i].fname == fname && bookings[i].lname == lname);
Here's what I have (updated code):
// ~~~ add bookings to localStorage
var bookings = JSON.parse(localStorage.getItem("bookings")) || [];
window.onload = showBooking();
$("#submit").click(function() {
var newBookings = {
fname: $('#fname').val(),
lname: $('#lname').val()
}
bookings.push(newBookings);
var json = JSON.stringify(bookings);
window.localStorage.setItem("bookings", json);
showBooking();
});
// ~~~ edit bookings in localStorage
$(document).on('click','#edit',function (e) {
e.preventDefault();
var parent_form = $(this.form);
var fname = parent_form.find('.input:eq(0)').val();
var lname = parent_form.find('.input:eq(1)').val();
const i = bookings.findIndex(booking => bookings.fname == fname && bookings.lname == lname);
deleteBooking(i);
bookings.push({
fname,
lname
});
var json = JSON.stringify(bookings);
window.localStorage.setItem("bookings", json);
// showBooking();
});
// ~~~ display bookings in browser
function showBooking() {
var bookingResult = document.getElementById("result");
var ul = document.createElement("ul");
// var bookingItems = JSON.parse(localStorage.getItem("bookings")) || [];
bookingResult.innerHTML = "";
for (let i = 0; i < bookings.length; i++) {
bookingResult.innerHTML += `<div class="card card-body bg-light m-4">
<h3>${bookings[i].fname + " " + bookings[i].lname}
<button onclick="deleteBooking(${i})" class="btn btn-danger text-light ">Delete</button>
<button onclick="editBooking(${i})" class="btn btn-danger text-light ">Edit</button>
</h3>
</div>`;
}
}
// ~~~ edit bookings in browser
function editBooking(i) {
// $('#regForm').hide();
$('#result').hide();
var currentItem = document.getElementById("currentItem");
var editBooking = document.getElementById("editAppt");
currentItem.innerHTML += `<div class="card card-body bg-light m-4">
<h3>${bookings[i].fname + " " + bookings[i].lname} </h3>
</div>`;
editBooking.innerHTML = `<input type="text" class="input" id="fname_${i}" placeholder="${bookings[i].fname}" name="${bookings[i].fname}" value="${bookings[i].fname}" required>
<input type="text" class="input" id="lname_${i}" placeholder="${bookings[i].lname}" name="${bookings[i].lname}" value="${bookings[i].lname}" required>
<input id="edit" type="submit" value="Edit">`;
}
// ~~~ delete bookings from localStorage
function deleteBooking(i) {
bookings.splice(i, 1);
localStorage.setItem("bookings", JSON.stringify(bookings));
showBooking();
}
My HTML form:
<form id="regForm" name="regForm" action="" class="col-sm-6">
<div class="row">
<input type="text" class="input" id="fname" placeholder="First Name" name="fname" required>
<input type="text" class="input" id="lname"placeholder="Last Name" name="lname" required>
<input id="submit" type="submit" value="Submit">
</div>
</form>
<div id="result" class="row"></div>
<div id="currentItem" class="row"></div>
<div id="editAppt" class="row"></div>
There are several changes you need to consider
You have bookings AND bookingItems
You do some changes (I assume there will be some destination change) but do not save them
You parse the localStorage far too often. Not needed. Only read once and write when modified
You cannot have duplicate IDs so you need to delegate and use class names
Be consistent and use jQuery to create elements and to add events- for example the delete button should be d er legates and remove its closest form element
Here is how to find the booking based on names
const idx = bookings.findIndex(booking => bookings.fname == fname && bookings.lname == lname);
I have two buttons ... when clicked they display some text in a input field. I use some simple javascript to select which text to display, the one defined under the button with id="blabla1" or the one under the button with id="blabla2".
Is it possible to display the text defined in an external .txt file?
It is working fine with the text defined as value under the input button:
<input type="hidden" id="SupSite1Title" value="Subsite1 Title!"><br>
but i want text from a txt file instead.
<body>
<div id="leftnav">
<ul>
<li><input type="text" id="TextField1"><br><br></li>
</ul>
</div>
<div id="rightnav">
<ul>
<li><button id="blabla1" onclick="myFunction1()">Side1</button></li>
<li><button id="blabla2" onclick="myFunction2()">Side2</button></li>
</ul>
</div>
<input type="hidden" id="SupSite1Title" value="Subsite1 Title!"><br>
<input type="hidden" id="SupSite2Title" value="Subsite2 Title!"><br>
<script>
function myFunction1() {document.getElementById("TextField1").value =document.getElementById("SupSite1Title").value;
}
</script>
<script>
function myFunction2() {document.getElementById("TextField1").value =document.getElementById("SupSite2Title").value;
}
</script>
If you want to display the text content of the .txt file ... you can use an API called FileReader API (you need to check if your browser supports that)
here is how you can do it :
UPDATED :
var file1 = document.getElementById('file1');
var file2 = document.getElementById('file2');
document.getElementById('bOne').addEventListener("click", function(){getFile(file1)})
document.getElementById('bTwo').addEventListener("click", function(){getFile(file2)})
function getFile(target) {
const input = target;
if ('files' in input && input.files.length > 0) {
placeFileContent(
document.getElementById('display'),
input.files[0])
}
}
function placeFileContent(target, file) {
readFileContent(file).then(content => {
target.value = content
}).catch(error => console.log(error))
}
function readFileContent(file) {
const reader = new FileReader()
return new Promise((resolve, reject) => {
reader.onload = event => resolve(event.target.result)
reader.onerror = error => reject(error)
reader.readAsText(file)
})
}
label {
display : block;
margin-top : 40px;
margin-bottom : 20px;
}
<label for="file1">Upload file 1 : </label>
<input type="file" accept=".txt" id="file1" name="file1">
<label for="file2">Upload file 2 : </label>
<input type="file" accept=".txt" id="file2" name="file2">
<button id="bOne">Display file1</button>
<button id="bTwo">Display file2</button>
<label for="file2">Selected file : </label>
<input type="text" id="display" for="display">
METHOD N°2 (data fetching from a server) :
function fetchData(buttonNumber) {
var btn1 = document.getElementById('b1')
var btn2 = document.getElementById('b2')
var display = document.getElementById('display')
//fetching data
if (buttonNumber == 1) {
//replace 'file1.txt' with your file URL
fetch('file1.txt').then(x => {
x.text().then(function(text) {
display.value = text
});
})
} else {
//replace 'file2.txt' with your file URL
fetch('file2.txt').then(x => {
x.text().then(function(text) {
display.value = text
});
})
}
}
#b1,
#b2 {
display: block;
margin: 40px;
}
<button id="b1" onclick="fetchData(1)">Get file 1 and show it</button>
<button id="b2" onclick="fetchData(2)">Get file 2 and show it</button>
<label for="file2">Selected file : </label>
<input type="text" id="display" for="display">
If you want to read the contents of a text file you cannot load it from local file system. You should put it on server and load it from there.
Give the input field the attributes type="file" and accept=".txt", and that should work
<input type="file" accept=".txt" />
And you can read this .txt file using node.js(Also you can read it with vanilla js), But i prefer node.js like this
const fs = require('fs');
const fileData = fs.readFileSync('fileName.txt', 'utf-8');
console.log(fileData) // Whatever inside .txt file
Update according to comment:
Suppose in your project folder, you have one index.html file and one index.js file. Create two .txt file named as file1.txt and file2.txt And write something on those file. NOTE: For simplicity i am writing solution using jQuery.
index.html
<body>
<p id="text-field"></p>
<button id="btn1">Button 1</button>
<button id="btn2">Button 2</button>
</body>
index.js
const fs = require('fs');
let fileData = '';
$('#btn1').click(()=> {
fileData = fs.readFileSync('file1.txt', 'utf-8');
$('#text-field').append(fileData);
});
$('#btn2').click(()=> {
fileData = fs.readFileSync('file2.txt', 'utf-8');
$('#text-field').append(fileData);
});
That's it. According to button click text will be append into p element.
You can handle two button click with one function also, like this
$('button').click(event => {
event.stopImmediatePropagation();
event.stopPropagation();
if($(event.target).attr('id') === 'btn1') {
fileData = fs.readFileSync('file1.txt', 'utf-8');
$('#text-field').append(fileData);
}else if($(event.target).attr('id') === 'btn2') {
fileData = fs.readFileSync('file2.txt', 'utf-8');
$('#text-field').append(fileData);
}
});
I want to be able to add jquery UI to the list on GoalNotes This table gets populated by what the user enters in the "name1" and "data1" input fields. Every time I give the an id, the program breaks and I get no errors. Any ideas on how I could apply animations to the table rows that get added after the user inputs data?
html
<section class="section section--active color1" data-letter="M">
<article class="section__wrapper">
<h1 class="section__title">Monday</h1>
<div id="Monday" class="tabcontent">
<form name="goalsList1" action = "/created" method="POST">
<div id="tab1">
<table>
<tr>
<td><b>New Goal:</b><input type="text" name="name1" id="name1"></td>
<td><b>Notes:</b><input type="text" name="data1" id="data1"></td>
<td>
<input type="submit" value="Save" onclick="SaveItem(1)">
</td>
</tr>
</table>
</div>
<div id="items_table1">
<h2>List of goals</h2>
<table id="list1" contenteditable> </table>
<p>
<label><input type="button" value="Clear" onclick="ClearAll(1)"></label>
</p>
</div>
</form>
</div>
</article>
</section>
javascript
function doShowAll(numOfWeek) {
if (CheckBrowser()) {
var key = "";
var list = "**<tr><th>Goal</th><th>Notes</th></tr>**\n";
var i = 0;
var goals = localStorage[numOfWeek] ? JSON.parse(localStorage[numOfWeek]) : {};
var goalsKeys = Object.keys(goals);
for (i = 0; i < goalsKeys.length; i++) {
key = goalsKeys[i];
list += "<tr><td>" + key + "</td>\n<td>"
+ goals[key] + "</td></tr>\n";
}
if (list == "<tr><th>Goal</th><th>Notes</th></tr>\n") {
list += "<tr><td><i>nothin' here</i></td>\n<td><i>nothin' here either</i></td></tr>\n";
}
document.getElementById('list'+numOfWeek).innerHTML = list;
} else {
alert('Cannot store list as your browser do not support local storage');
}
}
$(document).ready(function(e) {
$('#due-date').datepicker();
$('#add-todo').button({
icons: {
primary: "ui-icon-circle-plus"
}
}).click(function() {
$('#new-todo').dialog('open');
}); // end click
$('#new-todo').dialog({
modal: true,
autoOpen: false,
close: function() {
$('#new-todo input').val(''); /*clear fields*/
},
buttons : {
"Add task" : function() {
var taskName = $('#task').val();
var dueDate = $('#due-date').val();
var beginLi = '<li><span class="done">%</span><span class="delete">x</span>';
var taskLi = '<span class="task">' + taskName + '</span>';
var dateLi = '<span class="due-date">' + dueDate + '</span>';
var endLi = '</li>';
$('#todo-list').prepend(beginLi + taskLi + dateLi + endLi);
$('#todo-list').hide().slideDown(250).find('li:first')
.animate({
'background-color': '#ff99c2'
},250)
.animate({
'background-color': '#d9b3ff'
},250).animate; // end animate
$(this).dialog('close');
},
"Cancel" : function() {
$(this).dialog('close');
}
}
});
$('#todo-list').on('click','.done',function(e) {
var $taskItem = $(this).parent("li");
var $copy = $taskItem.clone();
$('#completed-list').prepend($copy);
$copy.hide().slideDown();
$taskItem.remove();
}
); // end on
$('#todo-list, #completed-list').on('click','.delete',function(e) {
$(this).parent("li").slideUp(250, function() {
$(this).remove();
}); // end slideup
}); // end on
$('#todo-list').sortable();
}); // end ready
http://jsbin.com/digefufeca/edit?html,css,js,console,output
The problem
The form with nane goalsList1 is sending whenever you click on the button.
Why? because the button is submit button.
The solution(s)
Replace the button's type to button. (link)
Prevent the form submission by event.preventDefault(). (link)
There are more ways but those are the major.
Note: your code still not working but now you can see the error message.