I want to have infinite file-upload buttons. Right after I send a file, a new button appears.
How can I do something like:
You can add an event listener to the element to listen for changes and set up createUploadButton function to trigger whenever the event is delivered.
element.addEventListener('change', createUploadButton);
The exact answer to your question is bellow:
function makeNewButton() {
//create an upload button:
let uploadbtn = document.createElement('input');
uploadbtn.setAttribute('type', 'file');
//append it to your document:
document.body.appendChild(uploadbtn);
//add an event listener that fires the function again:
uploadbtn.addEventListener('change', makeNewButton);
//make delete element:
let deletetext = document.createElement('p');
deletetext.textContent = 'Delete';
//append it to your document:
document.body.appendChild(deletetext);
//Add an event listener to remove the original button and the delete link on click:
deletetext.addEventListener('click', function() {
uploadbtn.remove();
deletetext.remove();
});
}
makeNewButton();
Full documentation to the document interface can be found here: https://developer.mozilla.org/en-US/docs/Web/API/Document
Handling the files and sending them to the server is a different mater.
Related
I'm working on my college's project and it's kind of like a web-text-based game. So I'm interested in a click event on a document to change the context and I did it with the code below.
The problem is that it keeps repeating everything and wont allow typing in the input.
const homepage = document.querySelector('#homepage')
document.addEventListener('click', function() {
/*I console.log to check that the function is still repeating*/
console.log('check')
homepage.innerHTML = `<div> hello what's your name? </div>`
document.addEventListener('click', function() {
homepage.innerHTML = `<div> my name is <br>
<input id="name"> </input> <br>
<button> submit </button<
`
})
})
#homepage {
text-align: center;
}
<div id="homepage"> click to change the content </div>
I will try to explain what is the exact issue that is happening below.
Here is your code
const homepage = document.querySelector('#homepage')
// You are adding a click event listner to your DOM
// This will trigger when ever you click on your html page
document.addEventListener('click', function () { // Code Section 1
console.log('this is a console log from first click event listner');
homepage.innerHTML = `<div> hello what's your name? </div>`;
// You are adding an another click event listner to your DOM
document.addEventListener('click', function () { // Code Section 2
console.log('this is a console log from second click event listner');
homepage.innerHTML = `<div> my name is <br>
<input id="name"> </input> <br>
<button> submit </button<
`;
})
})
#homepage {
text-align: center;
}
<div id="homepage"> click to change the content </div>
You have added a click event listner to your document using
document.addEventListener('click', function () {
(Refer Code Section 1 from the comment added in above code).
What this will do?
This will execute the entire set of code which is written inside that block when ever you click any where on your html page.
What is happening inside that code block?
Inside that code block, you are adding an another click event to the document using
document.addEventListener('click', function () {
(Refer Code Section 2 from the comment added in above code).
What happened till now?
You are now adding a click event listner, when ever the user clicks on the html application.
So what does this means?
This simply means that your code will keep on adding new click event listners whenever the user clicks on the application. So if the user click one time on the app, there will be two click event listner. If the user click the third time, one more event listner will be added, so that the total event listner will be three. This will keep on incrementing. This is happening because, you are keep on adding new click event listner when the pervious event listners exist.
So What wrong did happen? How to stop preventing the accumulation of event listners?
You have to revove the event listners before adding new event listners. You can make use of EventTarget.removeEventListener() for this purpose.
Implemetation using EventTarget.removeEventListener()
const homepage = document.querySelector('#homepage');
function listnerFunction() {
console.log('first click event triggered');
homepage.innerHTML = `<div> hello what's your name? </div>`;
// Removing the first event listner
document.removeEventListener('click', listnerFunction);
// Adding second event listner
document.addEventListener('click', secondListnerFunction);
}
function secondListnerFunction() {
console.log('second click event triggered');
homepage.innerHTML = `<div>
my name is <br>
<input id="name"> </input> <br>
<button> submit </button>
</div>
`;
// Removing the second event listner
document.removeEventListener('click', secondListnerFunction);
}
// You are registering click event to your complete html
document.addEventListener('click', listnerFunction);
#homepage {
text-align: center;
}
<div id="homepage"> click to change the content </div>
Explantion
Here I have added a click event listner function to the document using
document.addEventListener('click', listnerFunction);
What this will do?
This will trigger the function listnerFunction when the user clicks on the document.
Handling the second click from the first click event listner
Inside the first click event listner listnerFunction I have updated the innerHTML of your selected element. After this I have removed the first click event listner with
document.removeEventListener('click', listnerFunction);
There after I registered second click event listner with
document.addEventListener('click', secondListnerFunction);
What happens inside second click event listner?
Inside the second click event listner, I updated the innerHTML of your required target and I have removed the click event listner using
document.removeEventListener('click', secondListnerFunction);
This removing of the click event listner is required, after this whenever the user clicks the document, no events will be triggered and hence the user can use the app seamlessly.
const texts = [
"How are you?",
"Tired of studying?",
"Too long enough"
];
let textTake = 0;
document.addEventListener('click', ()=>{
if(textTake >= texts.length) textTake = 0;
document.getElementById("homepage").innerText = texts[textTake];
textTake++;
});
Here is a starter for you:
const homepage = document.querySelector('#homepage');
let html = [
"hello what's your name?",
'my name is <br> <input id="name"> <br> <button> submit </button>'
];
document.addEventListener('click',function(){
if (html.length) {
homepage.innerHTML = html.shift();
};
});
I have a table with some records in it and each of that records can be edited. I have a sidebar with edit form in it with the same inputs and the same submit button. When I try to execute the function on that button which will send an AJAX request, it executes as many times as many sidebars I opened before, when I need to update only that record which was actually edited.
That's the code:
// On Edit
$('.action-edit').on("click",function(e){
e.stopPropagation();
$(".add-new-data").addClass("show");
$(".overlay-bg").addClass("show");
const row = $(this).closest('td').parent('tr').first();
const agendaID = row.data('agenda_id');
const form = document.querySelector('#update_form');
const url = $(form).data('action_url').replace('.ID.', agendaID);
getAgendaInfo(agendaID);
$('.add-data-btn').on('click', function (e){
e.preventDefault();
console.log(agendaID); // displays IDs of all records where sidebar was opened.
const ajaxData = grabFormData();
editAgenda(url, row, ajaxData);
})
});
I think the issue is that you are adding new click event listener each time you show a new editor but you don't remove the previous event listener.
Try doing $('.add-data-btn').off() before the $('.add-data-btn').on('click'....
The problem you have is that your click handler is created whenever that .on() function is evaluated. The issue is that you execute that multiple times. Instead of that, you will need to perform a few steps for an elegant solution:
#1
Find a tag which exists before you populate your action-edit elements. In the worst case that would be body and I suggest that you need to start experimenting with
$(function() {
$('body').on("click", '.action-edit',function(e){
e.stopPropagation();
$(".add-new-data").addClass("show");
$(".overlay-bg").addClass("show");
const row = $(this).closest('td').parent('tr').first();
const agendaID = row.data('agenda_id');
const form = document.querySelector('#update_form');
const url = $(form).data('action_url').replace('.ID.', agendaID);
getAgendaInfo(agendaID);
$('.add-data-btn').on('click', function (e){
e.preventDefault();
console.log(agendaID); // displays IDs of all records where sidebar was opened.
const ajaxData = grabFormData();
editAgenda(url, row, ajaxData);
})
});
});
Note that this needs to run exactly once and will automatically create click handlers for you.
#2
Find the closest tag to your grid which already exists at the time the page is loaded and change the selector accordingly.
#3
Test, test, test
I have the following dialog box in my application:
When the user presses the Add logo button, following things should happen:
A file selectio dialog should pop up.
After the user has selected the file, a function should be called (which will update the image).
I have the following code for this. The markup for file selection looks like this:
<button class="btn" ng-click="$ctrl.addLogo()">Add logo</button>
$ctrl.addLogo() is defined as (source)
$ctrl.addLogo = function() {
console.log("'Add logo' button clicked");
var uploadForm = document.createElement('form');
var fileInput = uploadForm.appendChild(document.createElement('input'));
fileInput.type = 'file';
fileInput.name = 'images';
fileInput.multiple = true;
fileInput.click(function() {
console.log("Click callback called");
});
};
When I press the Add logo button, the file selection dialog does open, but the Click callback called message does not appear in the console. This means that I cannot detect, when the user has selected a file (or closed the dialog box with "Cancel").
How can I implement a reaction to the user selecting a file (or cancelling the dialog)?
When the user selects a file in an input with type="file", it is the change event that is fired.
If you replace your click listener by a change listener, it should work :)
fileInput.click(function() {
console.log("Click callback called");
});
must become:
fileInput.change(function() {
console.log("Click callback called");
});
I want to call the same action whenever the button is clicked, or the hash changed event occurred. Even if the hash changed event means just loading the page for the first time and redirecting to something like #something.
What I had so far, is basically duplicated code. The same code for a hashchange event, and for button clicked. I am looking for a solution not to have the code duplicated, but to call the hashchange event from a button clicked event. Here is my code so far.
main.js
$(window).bind('hashchange', function() {
// get User from the URL
var user = window.location.hash.substr(1);
// update the value in a text input with new ASIN
document.getElementById('asin_input').value = asin;
$.getJSON("/api/user/"+user, function (data) {
// ...
});
}).trigger('hashchange');
/*
* Whenever a button "Search!" is clicked, this function gets called.
*/
element.addEventListener('click', function () {
var user = $('#user_input').val();
$.getJSON("/api/user/"+user, function (data) {
// ...
});
});
Now the entire thing inside getJSON, and including the getJSON is duplicated, so I would want just the onClick calling/triggering the hashchange, which triggers getJSON. How to do this?
I have a form with multiple rows and each row has a delete button with a link. I want to progressively enhance the links to add a bootstrap modal to these buttons. So what I'm doing is:
Grab all the delete button elements on the page.
Loop through each button.
For each button and change some attributes on the modal based on what button is clicked, including the url that is called when "OK" is cicked.
Everything is working like I want, except that each time the modal is triggered and the "OK" button is clicked the url attached to that gets appended to the previous one.
http://jsfiddle.net/bittersweetryan/9TpX8/ (click the remove button then OK more than once, have your console open)
Here's the code
//anonymous function to grab all delete buttons and turn into a modal
(function(){
var delBtn = $(".delete"),
$modal = $("#modal-delete");
if(!$modal.size()){
$modal = $('<div id="modal-delete" class="modal hide fade"><div class="modal-header"> ×<h3>Confirm Delete</h3></div><div class="modal-body" id="modal-content"></div><div class="modal-footer"> OK Cancel </div></div>').appendTo("body");
}
delBtn.each(function(){
var $button = $(this),
clickHandler,
href= $button.attr("href");
if(href){
clickHandler = function(){
console.log(href);
//return window.location=href;
};
}
else{
clickHandler = $button.click;
}
$button.attr("data-toggle","modal").
attr("data-target","#modal-delete");
$button.on("click",function(){
$modal.find("#okButton").on("click",function(){
clickHandler();
$modal.modal('hide');
}).
end().
find("#cancelButton").on("click",function(){
$modal.modal('hide');
}).
end().
find("#modal-content").html($button.attr("title"));
});
});
})();
You attach another click handler to 'ok' every time you invoke a dialog. Quick fix:
$modal.find("#okButton").one("click",function(){
clickHandler();
$modal.modal('hide');
})
Your updated fiddle.
In general, binding handlers with jQuery sticks a new handler in the queue; it doesn't overwrite the existing handler with a new one.
After getting burned by this a number of times, mostly trying to properly bind to dynamically generated controls, I just started sticking
.unbind("click")
in the queue before setting up onclick bindings.
Some new fiddle.