Calling a function before callback function - javascript

I'm making to-do app and trying to run one function which is supposed to ran before callback function returns output. Callback fn is listening to click event and outputs user's input value to the screen. But before it happens, I want to first output h1 element on top with some text and then return callback function. How can I do this? I tried to use setInterval on the callback, but it didn't help. If user types something and clicks the add button, I want text "to-do list" appear on the most top and then after that the actual user's input itself. My code:
(function () {
var button = document.getElementsByTagName("button");
var userInput = document.getElementById("user_input");
function addItem() {
var li = document.createElement("li");
li.innerHTML = userInput.value;
document.getElementsByTagName("ul")[0].appendChild(li);
userInput.value = "";
}
function categorize() {
console.log(document.getElementById("todo").getElementsByTagName('li').length);
if (document.getElementById("todo").getElementsByTagName('li').length > 0 && document.getElementById("todo").getElementsByTagName('li').length < 2) {
var h1 = document.createElement("h1");
h1.innerHTML = "to-do";
document.getElementById("todo").appendChild(h1);
}
}
button[0].addEventListener("click", addItem, false);
button[0].addEventListener("click", categorize);
})();

Well there are some questions that needs to get answers here:
Why don't you just call categorize() function in the addItem and
use only addItem() as callback.
Why are you wrapping your whole code in an Immediately-Invoked Function Expression?
Why are you only showing the h1 element if there's only one element in the Todo list?
I tried to refactor your code so it makes more sense. This is a working Demo:
var button = document.getElementsByTagName("button");
var userInput = document.getElementById("user_input");
var entered = false;
function addItem() {
if(!entered){
categorize();
}
var li = document.createElement("li");
li.innerHTML = userInput.value;
document.getElementsByTagName("ul")[0].appendChild(li);
userInput.value = "";
}
function categorize() {
entered= true;
var h1 = document.createElement("h1");
h1.id = "title";
h1.innerHTML = "to-do";
document.getElementById("todo").appendChild(h1);
}
button[0].addEventListener("click", addItem, false);
<input type="text" id="user_input" />
<button>Add Item</button>
<div id="todo">
<ul></ul>
</div>

Try this :
button[0].addEventListener("click", function () { categorize(); addItem(); });
instead of this :
button[0].addEventListener("click", addItem, false);
button[0].addEventListener("click", categorize);

My suggestion is handling event mousedownthat is fired before click event
button[0].addEventListener.on('mousedown', categorize);

I have made minor updates to you code below. Please try and use this instead.
(function () {
var button = document.getElementsByTagName("button");
var userInput = document.getElementById("user_input");
function categorize() {
console.log(document.getElementById("todo").getElementsByTagName('li').length);
if (document.getElementById("todo").getElementsByTagName('li').length > 0 && document.getElementById("todo").getElementsByTagName('li').length < 2) {
var h1 = document.createElement("h1");
h1.innerHTML = "to-do";
document.getElementById("todo").appendChild(h1);
}
}
function addItem() {
categorize(); //since you want this to be executed before the code in addItem()
var li = document.createElement("li");
li.innerHTML = userInput.value;
document.getElementsByTagName("ul")[0].appendChild(li);
userInput.value = "";
}
button[0].addEventListener("click", addItem);
})()

Related

javascript - for loop - only every second event listener working

I am very new to web design so im sure im doing something silly here but i am really curious what i am doing wrong, I am doing an online udemy course and for some reason only every second iteration of the li's that i spawn appear to have my event listener attached and i cannot for the life of me figure out why. I am assuming it is something todo with my "this" when adding the event listener, i tried to change to a listObjects[i].classList.toggle but it just threw an error however strangely enough if i do a this.classList.add("done") it works perfectly. thanks in advance!
var enterBtn = document.querySelectorAll("button")[0];
var cancelBtn = document.querySelectorAll("button")[1];
var ul = document.querySelector("ul");
var listObjects
function addList(todo) {
var li = document.createElement("li");
li.appendChild(document.createTextNode(todo));
ul.appendChild(li);
listObjects = document.querySelectorAll("li");
setListDone();
}
enterBtn.addEventListener("click", function() {
var listData = document.querySelector("input").value;
addList(listData);
});
cancelBtn.addEventListener("click", function() {
ul.innerHTML = " ";
});
function setListDone() {
for (i = 0; i < listObjects.length; i++) {
listObjects[i].addEventListener("click", function() {
this.classList.toggle("done");
});
}
}
.done {
text-decoration: line-through;
}
<h1>Todo List</h1>
<input type="text">
<button>Enter</button>
<button>Cancel</button>
<ul>
</ul>
The reason is you are using setListDone to assign click to all li. So when you add second li it will assign click to first li also. So when you click on first li it will call click twice. Further if you add third li then on first li click it will call click three times.
To solve issue you just need to pass newly created li to setListDone and update your setListDone as below.
function setListDone(li) {
li.addEventListener("click", function() {
this.classList.toggle("done");
});
}
Test complete code below.
var enterBtn = document.querySelectorAll("button")[0];
var cancelBtn = document.querySelectorAll("button")[1];
var ul = document.querySelector("ul");
var listObjects
function addList(todo) {
var li = document.createElement("li");
li.appendChild(document.createTextNode(todo));
ul.appendChild(li);
listObjects = document.querySelectorAll("li");
setListDone(li);
}
enterBtn.addEventListener("click", function() {
var listData = document.querySelector("input").value;
addList(listData);
});
cancelBtn.addEventListener("click", function() {
ul.innerHTML = " ";
});
function setListDone(li) {
li.addEventListener("click", function() {
this.classList.toggle("done");
});
}
.done {
text-decoration: line-through;
}
<h1>Todo List</h1>
<input type="text">
<button>Enter</button>
<button>Cancel</button>
<ul>
</ul>
You're never removing the old event listeners, so anything with an even index is getting toggled twice (or four times, or whatever) and ending up in the same state as it started. If you clear the old event listener first (or only add them to newly created elements) the issue disappears:
var enterBtn = document.querySelectorAll("button")[0];
var cancelBtn = document.querySelectorAll("button")[1];
var ul = document.querySelector("ul");
var listObjects
function addList(todo) {
var li = document.createElement("li");
li.appendChild(document.createTextNode(todo));
ul.appendChild(li);
listObjects = document.querySelectorAll("li");
setListDone();
}
enterBtn.addEventListener("click", function() {
var listData = document.querySelector("input").value;
addList(listData);
});
cancelBtn.addEventListener("click", function() {
ul.innerHTML = " ";
});
function setListDone() {
for (i = 0; i < listObjects.length; i++) {
listObjects[i].removeEventListener("click", liClickHandler);
listObjects[i].addEventListener("click", liClickHandler);
}
}
function liClickHandler() {
this.classList.toggle("done");
}
.done {
text-decoration: line-through;
}
<h1>Todo List</h1>
<input type="text">
<button>Enter</button>
<button>Cancel</button>
<ul>
</ul>
Every time you add item to the list you add event listeners to every item. That's why some of the are trigged twice or event more.
listObjects[i].addEventListener("click", function() {
this.classList.toggle("done");
});
the simple solution is below.
you just need to add event listener to a single <li> every time you add element to the list.
var enterBtn = document.querySelectorAll("button")[0];
var cancelBtn = document.querySelectorAll("button")[1];
var ul = document.querySelector("ul");
var listObjects
function addList(todo) {
var li = document.createElement("li");
li.appendChild(document.createTextNode(todo));
// Here you add the listener to just created list item
li.addEventListener("click", function() {
this.classList.toggle("done");
});
ul.appendChild(li);
}
enterBtn.addEventListener("click", function() {
var listData = document.querySelector("input").value;
addList(listData);
});
cancelBtn.addEventListener("click", function() {
ul.innerHTML = " ";
});
.done {
text-decoration: line-through;
}
<h1>Todo List</h1>
<input type="text">
<button>Enter</button>
<button>Cancel</button>
<ul>
</ul>

Remove dynamically created elements by class name Javascript

So, in plain terms I am creating a Chrome Extension that so far can only save links from the internet but not delete them. What I want to add is a "remove" button for deleting unwanted links. So far I haven't got that to work.
The buttons I want to remove are added using JavaScript. Each new block of HTML features a "remove" button but clicking that button does nothing. I have tried binding listeners to each element using a for loop but that doesn't seem to work.
The code runs without errors and I'm certain that the issue is a slight oversight but I have only just started using JavaScript so I'm lost for solutions at the moment.
I have included all the code because I don't want to leave out anything that might be imperative to finding a solution.
It starts with the code for adding a link, followed by removing a single link and then removing all links at once. Thank you all for any help, really want to get this working.
https://github.com/mmmamer/Drop Repository for the rest of the code. Mainly popup.html and popup.css.
var urlList = [];
var i = 0;
document.addEventListener('DOMContentLoaded', function() {
getUrlListAndRestoreInDom();
// event listener for the button inside popup window
document.getElementById('save').addEventListener('click', addLink);
});
function addLink() {
var url = document.getElementById("saveLink").value;
addUrlToListAndSave(url);
addUrlToDom(url);
}
function getUrlListAndRestoreInDom() {
chrome.storage.local.get({
urlList: []
}, function(data) {
urlList = data.urlList;
urlList.forEach(function(url) {
addUrlToDom(url);
});
});
}
function addUrlToDom(url) {
// change the text message
document.getElementById("saved-pages").innerHTML = "<h2>Saved pages</h2>";
var newEntry = document.createElement('li');
var newLink = document.createElement('a');
var removeButton = document.createElement('button');
removeButton.textContent = "Remove";
//removeButton.createElement('button');
removeButton.type = "button";
removeButton.className = "remove";
newLink.textContent = url;
newLink.setAttribute('href', url);
newLink.setAttribute('target', '_blank');
newEntry.appendChild(newLink)
newEntry.appendChild(removeButton);
newEntry.className = "listItem";
document.getElementById("list").appendChild(newEntry);
}
function addUrlToListAndSave(url) {
urlList.push(url);
saveUrlList();
//}
}
function saveUrlList(callback) {
chrome.storage.local.set({
urlList
}, function() {
if (typeof callback === 'function') {
//If there was no callback provided, don't try to call it.
callback();
}
});
}
// remove a single bookmark item
document.addEventListener('DOMContentLoaded', function() {
getUrlListAndRestoreInDom();
var allButtons = document.getElementsByClassName('remove');
function listenI(i) {
allButtons[i].addEventListener('click', () => removeMe(i));
}
for (var i = 0; i < allButtons.length; i++) {
listenI(i);
}
});
function removeMe(i) {
var fullList = documents.getElementsByClassName('listItem');
listItem[i].parentNode.removeChild(listItem[i]);
}
//remove all button
document.addEventListener('DOMContentLoaded', function() {
document.getElementById("remove-all").addEventListener('click', function() {
var removeList = document.getElementsByClassName("listItem");
while(removeList[0]) {
removeList[0].parentNode.removeChild(removeList[0]);
}
})
});
chrome.storage.local.get() is asynchronous. So when you try to add the event listeners to the Remove buttons, they're not in the DOM yet.
You can add the listener in the addUrlToDom() function instead. That way you'll also add the event listener when you create new buttons.
function addUrlToDom(url) {
// change the text message
document.getElementById("saved-pages").innerHTML = "<h2>Saved pages</h2>";
var newEntry = document.createElement('li');
var newLink = document.createElement('a');
var removeButton = document.createElement('button');
removeButton.textContent = "Remove";
//removeButton.createElement('button');
removeButton.type = "button";
removeButton.className = "remove";
newLink.textContent = url;
newLink.setAttribute('href', url);
newLink.setAttribute('target', '_blank');
newEntry.appendChild(newLink)
newEntry.appendChild(removeButton);
removeButton.addEventListener("click", function() {
var anchor = this.previousElementSibling;
var url = anchor.getAttribute("href");
removeUrlAndSave(url);
this.parentNode.remove();
});
newEntry.className = "listItem";
document.getElementById("list").appendChild(newEntry);
}
function removeUrlAndSave(url) {
var index = urlList.indexOf(url);
if (index != -1) {
urlList.splice(index, 1);
saveUrlList();
}
}

onclick excecutes does not work, only when creating DOM

I have the following HTML and javascript.
I can create the buttons without any problem, but the onclick function does not work when clicking the button. It does not do anything.
If I put the method without the ' it excecutes when generating the form, one after the other generating 3 dialogs
function makeUL(array) {
var list = document.createElement('ul');
for (var i = 0; i < array.length; i++) {
var btn = document.createElement("BUTTON");
/*
btn.onClick = function () {
buttonClicked(array[i]);
};*/
var t = document.createTextNode(array[i]); // Create a text node
btn.appendChild(t); // Append the text to <button>
btn.type = "button"
btn.onClick = 'buttonClicked()';
list.appendChild(btn); // Append <button> to <body>
var nextLine = document.createElement("td");
list.appendChild(nextLine);
}
return list;
}
/*
function buttonClicked(buttonName){
alert(buttonName);
}*/
function buttonClicked() {
alert("algo");
}
self.onInit = function() {
var boton = [];
for (var g = 0; g < self.ctx.settings.Botones.length; g++) {
boton[0] = self.ctx.settings.Botones[g].btnId;
boton[1] = self.ctx.settings.Botones[g].method;
boton[2] = self.ctx.settings.Botones[g].params;
document.getElementById('myList').appendChild(makeUL(boton));
}
self.ctx.$scope.sendCommand = function() {
var timeout = self.ctx.settings.requestTimeout;
var rpcMethod = self.ctx.settings.method;
var rpcParams = self.ctx.settings.params;
var commandPromise;
commandPromise = self.ctx.controlApi.sendTwoWayCommand(rpcMethod, rpcParams, timeout);
commandPromise.then(
function success(response) {
//alert("Comando recibido exitosamente\n Respuesta:" + angular.toJson(response));
alert("Comando recibido exitosamente");
},
function fail(rejection) {
alert("ERROR AL ENVIAR COMANDO");
}
);
};
};
<form name="rpcForm">
<md-content class="md-padding" layout="column">
<div id="myList"></div>
</md-content>
</form>
The problem is:
btn.onClick = 'buttonClicked()';
It looks like you were trying to assign to the onclick attribute of the HTML, in which case the proper syntax would be
btn.setAttribute('onclick', 'buttonClicked()');
But since you already have a reference to the element, there's no need to resort to attributes; inline handlers are pretty bad practice anyway. Change to:
btn.onclick = buttonClicked;
(note the lower-case c in onclick), or
btn.addEventListener('click', buttonClicked);
Also, you might consider simply assigning to the button's textContent rather than creating a text node explicitly, it's a bit easier to read and write: change
var t = document.createTextNode(array[i]); // Create a text node
btn.appendChild(t); // Append the text to <button>
to
btn.textContent = array[i];

Javascript button toggle

I am trying to write a javascript function so that when a button is clicked, all HTML paragraph elements "p" will be highlighted yellow, the HTML buttons text will then change to "Click to unhighlight" (the code below before the else statement is fully functional, all paragraphs are highlighted and the buttons text changes). I am trying to reload the page using "location.reload();" but it doesn't seem to work.
window.onload = function() {
var button = document.getElementsByTagName("button");
button[0].onclick = changeBackground;
}
function changeBackground() {
var myParas = document.getElementsByTagName("p");
for (var i = 0; i < myParas.length; i++) {
myParas[i].style.backgroundColor = "yellow";
}
var firstClick = true;
var b = document.getElementById("button");
if (firstClick) {
b.innerHTML = "Click to unhighlight";
firstClick = false;
} else {
location.reload();
firstClick = true;
}
}
Any advice on how to properly call the "location.reload();" function would be much appreciated. Thanks in advance.
Your main issue is that you have:
var firstClick = true;
inside the click event handler so every time the button is clicked, it thinks it's the first click. You'd need to have that set outside of the event handler and inside, you'd want to toggle it to the opposite of its current value:
var firstClick = true;
function changeBackground() {
var myParas = document.getElementsByTagName("p");
for (var i = 0; i < myParas.length; i++) {
myParas[i].style.backgroundColor = "yellow";
}
var b = document.getElementById("button");
if (firstClick) {
b.textContent = "Click to unhighlight";
} else {
location.reload();
}
firstClick = !firstClick; // Toggle the first click variable
}
But, really instead of reloading the document, just un-highlight the paragraphs. Reloading takes more resources.
Avoid using getElementsByTagName() as it returns a "live node list", which has performance implications.
Also, rather than set up an explicit onload event handler, just position your code at the bottom of the HTML body.
Lastly, use modern standards for event handling (.addEventListener), rather than event properties (onclick).
See comments inline below:
// Place all this code inside of a `<script>` element and place that
// element at the bottom of the code, just before the closing body tag.
let btn = document.querySelector("button");
// Modern, standards-based way to set up event handlers
btn.addEventListener("click", changeBackground);
function changeBackground() {
// Use .querySelectorAll() and convert the results to an array
var myParas = Array.prototype.slice.call(document.querySelectorAll("p"));
// Loop over all the paragraphs
myParas.forEach(function(par){
// Toggle the CSS class to highlight/or unhighlight them
par.classList.toggle("highlight");
});
// Set the button text accordingly
btn.textContent = myParas[0].classList.contains("highlight") ? "Click to unhighlight" : "Click to highlight";
}
.highlight { background-color:yellow; }
<p>This is a test</p>
<h1>This is a test</h1>
<p>This is a test</p>
<p>This is a test</p>
<div>This is a test</div>
<p>This is a test</p>
<p>This is a test</p>
<button>Click to highlight</button>
the problem is that the else sentence never be call, because the "firstClick" variable always will be true each time you call the changeBackGround method you're setting the variable to true.
to avoid this, just declare the variable out of the method, example:
var firstClick=true;
function changeBackground(){
var myParas = document.getElementsByTagName("p");
for (var i = 0; i < myParas.length; i++) {
myParas[i].style.backgroundColor = "yellow";
}
var b = document.getElementById("button");
if (firstClick){
b.innerHTML = "Click to unhighlight";
firstClick = false;
}else{
location.reload();
firstClick = true;
}
}
A different approach is to use switch case.
<button id="changeButton">Make my paragraphs Yellow</button>
<script>
var theToggle = document.getElementById("changeButton");
var toggleMe = document.getElementsByTagName("p");
toggleMe.toggleStatus = "on";
theToggle.onclick = function(){
switch(toggleMe.toggleStatus){
case "on":
toggleMe.toggleStatus="off";
for (var i = 0; i < toggleMe.length; i++) { toggleMe[i].style.backgroundColor = 'yellow'; }
theToggle.textContent = "Make my paragraphs White";
break;
case "off":
toggleMe.toggleStatus="on";
for (var i = 0; i < toggleMe.length; i++) { toggleMe[i].style.backgroundColor = 'white'; }
theToggle.textContent = "Make my paragraphs Yellow";
break;
}
}
</script>
Hope that solve it.

Why does this javascript function activate at the wrong time?

Here's the code I'm currently using
function firstChildAge() {
var header = document.createElement('H3');
var body = document.getElementsByTagName('BODY');
var textnode = document.createTextNode("WHAT IS THE AGE OF THE FIRST CHILD?");
var inputChildOne = document.createElement("Input");
var childOneAgeResponse = inputChildOne.value;
header.appendChild(textnode);
document.body.appendChild(header);
document.body.appendChild(inputChildOne);
}
function submitButton() {
var btn = document.createElement('Button');
document.body.appendChild(btn);
btn.onClick = testFunction_2();
}
function testFunction_2() {
alert("foo");
}
if (childrenResponse == 1) {
firstChildAge();
submitButton();
}
As you can see, if childrenResponse (the user's response to a previous query) is equal to 1, both functions are activated. The attempted goal is to create a text node, an input, and a button. The button as of right now, should active testFunction2() which alerts us that it is working. But, testFunction2() activates before the text node or input even shows up. I can find the reason for this, and if anyone can help me out I'd greatly appreciate it. Thank you.
Also, on a side note, how can I add text to the button created in submitButton() ? Thanks!
You have called the testFunction_2, instead of assigning it. This should work out fine.
function submitButton() {
var btn = document.createElement('Button');
btn.onclick = testFunction_2;
document.body.appendChild(btn);
}
You are calling the function testFunction_2() in onClick. You need to add event listener to button as shown below
btn.addEventListener('click', testFunction_2);
To add text to button use
var txt = document.createTextNode("CLICK ME");
btn.appendChild(txt);
Check the snippet below
function firstChildAge() {
var header = document.createElement('H3');
var body = document.getElementsByTagName('BODY');
var textnode = document.createTextNode("WHAT IS THE AGE OF THE FIRST CHILD?");
var inputChildOne = document.createElement("Input");
var childOneAgeResponse = inputChildOne.value;
header.appendChild(textnode);
document.body.appendChild(header);
document.body.appendChild(inputChildOne);
}
function submitButton() {
var btn = document.createElement('Button');
var txt = document.createTextNode("CLICK ME");
btn.appendChild(txt);
document.body.appendChild(btn);
btn.addEventListener('click', testFunction_2);
}
function testFunction_2() {
alert("foo");
}
childrenResponse = 1;
if (childrenResponse == 1) {
firstChildAge();
submitButton();
}
You are calling the function testFunction_2 in onClick. You need to provide reference.
That also won't work. You need to add event listener to button.
And for setting the text, just set innerHTML of button.
var btn = document.createElement('Button');
btn.innerHTML = "click";
btn.addEventListener('click', testFunction_2);
document.body.appendChild(btn);
btn.onclick = testFunction_2; // in place of addEventListener.
// if you want to use onclick. use small case 'c' in onclick.
There were 2 problems:
onClick should've been onclick.
You were executing the function and assigning the result of that function to the onclick. btn.onClick = testFunction_2(); should be btn.onClick = testFunction_2;
See working snippet below.
function firstChildAge() {
var header = document.createElement('H3');
var body = document.getElementsByTagName('BODY');
var textnode = document.createTextNode("WHAT IS THE AGE OF THE FIRST CHILD?");
var inputChildOne = document.createElement("Input");
var childOneAgeResponse = inputChildOne.value;
header.appendChild(textnode);
document.body.appendChild(header);
document.body.appendChild(inputChildOne);
}
function testFunction_2() {
alert("foo");
}
function submitButton() {
var btn = document.createElement('button');
btn.innerHTML = "Some button name";
btn.onclick = testFunction_2;
document.body.appendChild(btn);
}
var childrenResponse = 1;
if (childrenResponse == 1) {
firstChildAge();
submitButton();
}
In javascript you can use the innerHTML set the button's HTML contents.
See Setting button text via javascript
btn.innerHTML = "This is a button name";
The Mozilla Developer Network is a good resource. Here's two links for the above mentioned snippets.
MDN innerHTML
MDN HTML Button element

Categories

Resources