I am trying to program a click function that if a certain condition is true, each time the button is clicked it will overwrite the current string and replace it with a new string character.
I created a simple example below to illustrate what I am trying to accomplish.
$(document).ready(function() {
const hello = document.getElementById("hi");
const button =
document.getElementById("replace");
let clicked = false;
let goodBye = function() {
clicked = true;
if (hello.innerHTML.length < 9) {
if (clicked) {
// I want to clear the current HTML first, then I went the new HTML to add a single 9 every time the button is clicked.
hello.innerHTML += "9";
}
}
}
button.addEventListener("click", goodBye);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1 id="hi">01234567</h1>
<button id="replace">click me</button>
While I'm sure this is very simple I'm still relatively new to working with JS and I've been stuck trying to figure this out for over a week now. Any help is appreciated.
I removed your jQuery as it's not needed. I believe this is what you are looking for.
Steps:
Obtain a reference to your elements (hello and button)
Bind an event listener to your button click
When button is clicked, get the current value of your hello element
Run logic (if statement) and do what you need.
https://jsfiddle.net/3ho2by8t/14/
(() => {
const hello = document.getElementById("hi");
const button = document.getElementById("replace");
button.addEventListener('click', (evt) => {
const helloText = hello.innerHTML;
if (helloText.length > 9) {
hello.innerHTML = '9';
} else {
hello.innerHTML += helloText.length;
}
});
})();
<h1 id="hi">01234567</h1>
<button id="replace">click me</button>
Related
my main project is too complicated to show here so I created a small script demonstrating the problem I am working on. In simple terms, I need to create a button that once clicked, generates a button that also has an event listener that returns that button's id to the console.
See code below:
button_number = 0
create_buttons = document.getElementById('create_buttons')
div = document.getElementById('div')
create_buttons.addEventListener('click', e=>{
button_number += 1
new_button = document.createElement('button')
new_button.setAttribute('id', 'button'+button_number)
new_button.innerHTML = 'What number am I?'
new_button.addEventListener('click', show_button_number)
div.appendChild(new_button)
})
function show_button_number () {
let number = button_number
button = document.getElementById('button' + number)
console.log(button.id)
}
<div id="div">
<button id="create_buttons">Create a button!</button>
</div>
As written, all generated buttons return the button id of the most recently generated button versus their own id. Is there anyway I can change the anonymous function to return the button id of the button that was clicked? In order to integrate this into my main project, I need to create the event listener for the dynamically generated buttons using an anonymous function.
You could make a higher-order function, one that takes the current button number as an argument and returns a function using it:
const makeListener = num => () => {
const button = document.getElementById('button' + num)
console.log(button.id)
};
new_button.addEventListener('click', makeListener(button_number))
Or, you may not need the ID at all, just pass the element itself:
create_buttons.addEventListener('click', e=>{
const btn = div.appendChild(document.createElement('button'));
btn.textContent = 'What number am I?'
btn.addEventListener('click', () => {
console.log(new_button);
});
});
The major way to do that is to use event delegation mechanim
const divParent = document.getElementById('div')
var button_number = 0
divParent.addEventListener('click', e =>
{
if (!e.target.matches('button')) return // ignore clicks from other things
if (e.target.id === 'create_buttons')
{
let new_button = document.createElement('button')
new_button.id = 'button' + ++button_number
new_button.textContent = 'What number am I?'
divParent.appendChild(new_button)
}
else
{
console.clear()
console.log( e.target.id )
}
})
<div id="div">
<button id="create_buttons">Create a button!</button>
</div>
I have a little problem that I replicated in the little code snippet below (in the most simple way possible, however it still shows the problem I am facing).
Here is the snippet :
const searchBar = document.getElementById('search');
const resBox = document.getElementById('results');
searchBar.addEventListener('input', function handler(e) {
if (e.target.value === '') {
resBox.innerHTML = '';
return false;
}
setTimeout(() => populate(e), 300);
});
function populate(e) {
const btnBox = document.createElement('div');
for (let i = 1; i <= 3; i++) {
const btn = document.createElement('button');
btn.classList.add('js-click')
btn.innerText = 'Click me';
btnBox.appendChild(btn);
}
resBox.appendChild(btnBox);
dynamicBtnClickListener();
}
function dynamicBtnClickListener() {
resBox.addEventListener('click', function handler(e) {
console.log('You clicked me !');
});
// THE SOLUTION I FOUND FOR THE MOMENT :
//const btns = document.querySelectorAll('button.js-click');
//btns.forEach(btn => {
// btn.addEventListener('click', function handler(e) {
// console.log('You clicked me !');
// });
//});
}
<input type="text" id="search">
<div id="results"></div>
As you can see in the snippet, I have a first listener on input that generates a list of buttons when you type in it. When it is empty, the buttons disappear. In my real world case, it is a search input, that when a user types in, calls a function that populates a result box below it with results from DB.
I then have an on click listener on the buttons. In the code snippet, I simply put a console('You clicked me') when you click on the buttons. In my real app, it takes the result item (each result is an user) and inserts it in a table.
The problem appears when you open, close, then re-open the results box. This is done by inputing something, clearing the input, then re-input something. When you do that and then click on one of the buttons, it fires the click event on them as many times as you opened / closed the result box, so you will see the "You clicked me" on console multiple times.
I have done some research and most of it calls for using event.stopPropagation() and / or removing the event listener(s). I did try all these possible solutions, in every way I could think of, but I couldn't make it work.
Anyways I found a way around this (the commented portion of the dynamicBtnClickListener() function), but I feel it is not optimal. It consists of getting all the buttons with querySelectorAll(), then loop through them and add the click listener to every one of them, but I do not think it is optimal nor best-practice like. This is why I come here to ask if maybe there is a better solution, possibly one that keeps the click listener on the results box (if that is the most optimal solution. Is it by the way ?).
So even though I found a solution to this problem, could someone please tell me what is the best practice and optimal way of doing this ?
Thank you very much for your help
Each time the you type in the text area, resBox is accessed each time and the actual element resBox gets a new event listener every time(the buttons don't have any specific listener themselves, so I make EACH BUTTON have a specific listener individually)
const searchBar = document.getElementById('search');
const resBox = document.getElementById('results');
searchBar.addEventListener('input', function handler(e) {
if (e.target.value === '') {
resBox.innerHTML = '';
return false;
}
setTimeout(() => populate(e), 300);
});
function populate(e) {
const btnBox = document.createElement('div');
for (let i = 1; i <= 3; i++) {
const btn = document.createElement('button');
btn.classList.add('js-click')
btn.innerText = 'Click me';
btn.addEventListener('click',function(ev){console.log('You clicked me !')})
btnBox.appendChild(btn);
}
resBox.appendChild(btnBox);
}
<input type="text" id="search">
<div id="results"></div>
Now, here is an example that only has one event listener but would completely handle the situation >:D
Technically this should be faster(since one event listener compared to many), but personally I prefer this option because it "feels better" due to one function controlling the whole button layout(which would make it less "rigid")
PS: The speed difference is so insignificant, you can pick and choose(but if a whole chuck ton of buttons, yea this becomes better)
const searchBar = document.getElementById('search');
const resBox = document.getElementById('results');
const randChars=()=>{ //random characters to prove ONE event listener can work for multiple buttons in resBox
let arr=["a","b","c","d","e"]
let randIndex=()=>Math.floor(Math.random()*arr.length)||1
let n=randIndex(); let returnChar=""
for(let i=0;i<n;i++){returnChar+=arr[randIndex()]}
return returnChar
}
searchBar.addEventListener('input', function handler(e) {
if (e.target.value === '') {
resBox.innerHTML = '';
return false;
}
setTimeout(() => populate(e), 300);
});
resBox.addEventListener('click',function(ev){ //single event listener for all buttons
let currentButton=ev.path[0]
if(currentButton.tagName!="BUTTON"){return;} //if a button was not clicked
console.log("Button with text\n'"+currentButton.innerText+"'\nwas clicked")
})
function populate(e) {
const btnBox = document.createElement('div');
for (let i = 1; i <= 3; i++) {
const btn = document.createElement('button');
btn.classList.add('js-click')
btn.innerText = 'Click me '+randChars();
btnBox.appendChild(btn);
}
resBox.appendChild(btnBox);
}
<input type="text" id="search">
<div id="results"></div>
This question already has answers here:
How do I add an underline for all the links on the website when I click the button?
(2 answers)
Closed 2 years ago.
maybe one of you can help me. I've written a feature in javascript that adds underlining to all "a" selectors. The function is called with the "onclick" attribute. I would like to reverse the effect, i.e. remove the underscore at second click on the same button. The question is how to do it ?
HTML code:
<button type="button" class="underlineLinks" id="underlineLinks" onclick="underlineLinks()">Click</button>
JS code:
function underlineLinks() {
const links = document.querySelectorAll("a");
links.forEach(a => a.style.textDecoration = "underline");
}
You can create a CSS class with the decoration underline
.class
{
text-decoration: underline
}
and use toggle in the JS.
Toggle will add the class if it isn't applied to your link and remove the class if it is applied to your link
function underlineLinks() {
const links = document.querySelectorAll("a");
links.forEach(a => a.classList.toggle("class"));
}
https://jsfiddle.net/u4sxfdy5/
you could do this
function getUnderLineLinksSetter() {
let areLinksUnderlines = false;
return () => {
const links = document.querySelectorAll('a');
areLinksUnderlines = !areLinksUnderlines;
links.forEach(a => {
if (areLinksUnderlines) {
a.style.textDecoration = 'initial';
} else {
a.style.textDecoration = 'underline';
}
});
};
}
and then use the following html
<button type="button" class="underlineLinks" id="underlineLinks" onclick="getUnderLineLinksSetter()()">Click</button>
Its better to add event listeners from code and not using html inline functions by that i mean instead of setting the on click using html, you set it using javascript like this
// put this code inside a load event in the page so you make sure the button is in the dom
function getUnderLineLinksSetter() {
let areLinksUnderlines = false;
return () => {
const links = document.querySelectorAll('a');
areLinksUnderlines = !areLinksUnderlines;
links.forEach(a => {
if (areLinksUnderlines) {
a.style.textDecoration = 'initial';
} else {
a.style.textDecoration = 'underline';
}
});
};
}
document.getElementById('underlineLinks').addEventLisetner('click', getUnderLineLinksSetter())
And then remove the onclick from html
<button type="button" class="underlineLinks" id="underlineLinks">Click</button>
function underlineLinks() {
const links = document.querySelectorAll("a");
var toChange = "underline"
if(links[0].style.textDecoration != "underline")) toChange = "none"
links.forEach(a => a.style.textDecoration = toChange);
}
Probably there is an easier way but idk, I shoot my shot
I am trying to make a simple Shopping List App in which user can Add, Delete and mark the task done when completed. So far, I am able to add the task but facing problem in executing the done and delete functions. I am getting an error because when I execute it, the done and delete buttons are not there but what should I do to fix it?
var inp = document.getElementById("form");
var button = document.getElementById("click");
//Create List Function with Done and Delete Buttons
function addVal() {
var ul = document.getElementById("list");
var li = document.createElement("li");
var span = document.createElement("span");
var done = document.createElement("button");
var del = document.createElement("button");
li.appendChild(document.createTextNode(""));
span.appendChild(document.createTextNode(inp.value));
done.appendChild(document.createTextNode("Done"));
del.appendChild(document.createTextNode("Delete"));
li.appendChild(span);
li.appendChild(done);
li.appendChild(del);
done.setAttribute("class", "doneBut");
del.setAttribute("class", "delBut");
ul.appendChild(li);
inp.value = "";
}
//Get Input Length
function checkLength() {
return inp.value.length;
}
//Run function on Button Click
function onButtonClick() {
if (checkLength() > 0) {
addVal();
}
}
//Run function on Enter Keypress
function onEnter(event) {
if (checkLength() > 0 && event.which === 13) {
addVal();
}
}
//Trigger Events
button.addEventListener("click", onButtonClick);
inp.addEventListener("keypress", onEnter);
//Done and Delete Button Functions
var doneButton = document.getElementsByClassName("doneBut");
var deleteButton = document.getElementsByClassName("delBut");
function doneTask() {
doneButton.parentNode.classList.add("done");
}
function delTask() {
deleteButton.parentNode.classList.add("delete");
}
doneButton.addEventListener("click", doneTask);
deleteButton.addEventListener("click", delTask);
<input type="text" placeholder="Enter Your Task..." id="form" />
<button id="click">Add Task</button>
<h2>List:</h2>
<ul id="list"></ul>
Please Help.
Your problem is that the code tries to add events before the buttons exist. The buttons don’t exist until the addVal function gets called. Since addVal is not being called before the you try to add your event handlers, the getElementById returns null, and you attempt to add an event listener to null.
Additionally it looks like you’re planning to add multiple done and delete buttons. That wouldn’t normally be a problem, except you’re referencing them by ID, and IDs MUST be unique. You’ll need to switch this to a class or an attribute, since you’ll need one per item in the shopping cart.
You’ll probably want to look into event delegation, so that you can add your events once to the page before any buttons exist. https://javascript.info/event-delegation
It's most likely because your script is running before your code is running. Add the <script> tags just before the closing </body> tag to fix it:
<script>/* Your code here */</script>
</body>
You need to place this in a window.onload function, or run it in a function inside of the body tag's onload. Those elements don't exist yet when the script is run:
window.onload = function() {
var inp = document.getElementById("form");
var button = document.getElementById("click");
button.addEventListener("click", onButtonClick);
inp.addEventListener("keypress", onEnter);
}
As I am learning javascript I was testing different things. I made a small function:
foo("div", "button");
function foo(divId, buttonId)
{
var flag = 1;
var button2;
document.getElementById(buttonId).onclick = function() {
if (flag) {
button2 = createButton("Ceaning Service");
var span = createSpan("I will be removed");
var div = document.getElementById(divId);
div.appendChild(span);
document.body.insertBefore(button1, div);
flag = 0;
}
if (!flag) {
button2.onclick = function() {
div.removeChild(span);
document.body.removeChild(button1);
flag = 1;
return;
}
}
}
}
function createButton(text)
{
var button = document.createElement("BUTTON");
button.innerHTML = text;
return button;
}
function createSpan(text)
{
var span = document.createElement("SPAN");
span.innerHTML = text;
return span;
}
I can click the second button without errors only when I click the first button Click Me once. When I click Click Me button more than once and try to click the second button, it shows div is undefined. (span is undefined too, but it won't show because browser reaches div first).
Html:
<!DOCTYPE html>
<html>
<head>
<title>Testing</title>
</head>
<body>
<button id="button">Click Me</button><br>
<div id="div"></div>
<script src="test3.js"></script>
</body>
</html>
I played around with this function and when I declare span and div before ...(buttonId).onclick =... it works.
So why this code only works when I click Click Me once? I think with the second click it cannot reference to the created elements, but not sure why.
And although it removes those elements, will they be removed by the garbage collection as well or is there some kind of a memory leak happening?
And please try not to reference jQuery or some other libraries/frameworks. It would only complicate things for me for now.