I'm trying to write a code to change the innerHTML of a single element according to the elements touched by the user. The text has to be taken from the first child of the element touched. After the function is fired once, it doesn't fire anymore.
I wrote this:
let title = document.getElementById("title"); //element to be changed
let elements = document.getElementsByClassName("elements"); //touchable elements
for (i = 0; i < elements.length; i++) {
let ele = elements[i];
ele.addEventListener("touchstart", function() {
title.innerHTML = ele.firstChild.innerHTML;
})
}
I wrote an analogous code to work on desktop and, with click events, it works.
Where am I doing wrong?
Related
I have a weird problem with my simple to-do app. Its main features are adding new elements to "ul" and clicking on "li" to change its class. After clicking element it also adds an "i" with font-awesome icon and after clicking it again it should remove it. It works fine when I click added elements from top to bottom, but when I click from bottom to top, "i" is removed only from the first element from top. I can't figure out why is that, so I would appreciate any help.
Here is live demo where you can reproduce this bug:
https://michalgrochowski.github.io/to-do/
And here is the code responsible for that action:
document.getElementById("list").addEventListener("click", function(e) {
if (e.target && e.target.matches("li.item")) {
e.target.className = "itemDone";
var check = document.createElement("i");
check.className = "fa fa-check done";
e.target.appendChild(check);
} else if (e.target && e.target.matches("li.itemDone")) {
e.target.className = "item";
var done = document.getElementsByClassName("done");
var i;
for (i = 0; i < done.length; i++) {
e.target.removeChild(done[i]);
};
};
});
I've tested it in firefox and chrome, so it's not browser-related, it must be something in the code. I was thinking maybe the problem is with the loop inside the function, but I don't know how to change it.
var done = document.getElementsByClassName("done"); gets a list of all the .done elements in your document (including those who aren't child elements of e.target). So when executing e.target.removeChild(done[i]) if the current done[i] is a child of e.target, it will be removed, otherwise it will throw an error saying that the element done[i] is not a child of e.target. Try this:
var done = e.target.getElementsByClassName("done");
Note: if there could be sub-elements (children of children ...) of e.target that have the class .done. This will throw an error too. Because then the sub-children won't be direct children of e.target. removeChild work only on direct children. You can avoid trouble by using this:
var done = e.target.children; // to get the direct children only
var i;
for (i = 0; i < done.length; i++) {
if(done[i].matches('.done') // if it matches the criteria
e.target.removeChild(done[i]); // remove it
}
I'm having a little trouble adding an event listener to elements created dynamically.
I have a list of objects that represent matches a player plays in. And a for loop that iterates through them, creating 4 buttons for each match, a +1, a +2, a -1 and an END button.
However, even if they are well created, and appended where they should be, the event listeners are not kept. Here's a sample of my code:
var container = document.getElementById('container');
for (var i = 0; i < matches.length; i++) {
var row = document.createElement("div");
row.className = "row";
var plusOne = document.createElement("a");
plusOne.id = "plusone_ " + matches[i].id;
plusOne.addEventListener('click', function () {
alert('Clicked on plusOne!')
});
...
// adding plus two, minus one and END the same way
// however, END does have an eventListener on click
row.appendChild(plusOne);
container.appendChild(row);
}
If anyone has any idea why?
I am aware I can use the click function to attach an event to the DIV element but for some reason it is not working for me. Here is how I am creating the DIV element.
function createColorSwatchDiv(color) {
var colorSwatchDiv = $("<div>");
var image = $("<img>");
image.attr("src",color.imageURL);
var label = $("<label>");
label.text(color.title);
colorSwatchDiv.append(image);
return colorSwatchDiv;
}
Then I try to attach the click event like the following:
// run a loop and build the grid layout
for(index = 0; index < colors.length; index++) {
var colorSwatchDiv = createColorSwatchDiv(colors[index]);
// attach the event
colorSwatchDiv.click(function(){
alert('hello world');
});
colorsSection.append(colorSwatchDiv);
}
// add to the dom
$("#color .imageChartOption").after(colorsSection);
But it does not work and no click event is been attached.
following is the code
var $newdiv1 = $("<div id='object1' onClick=Test()>Hello</div>");
$("body").append($newdiv1);
function Test()
{
alert("Clicked");
}
OR
$newdiv1.on('click',function(){alert("hello");});
since you have created the div in a jQuery wrapper you don't need to wrap it again here $(colorSwatchDiv).click(.... Also, are you sure that the colorSwatchDiv variable is referencing the dom element and not the in memory element? Can you apply a class or anything to the elm in the dom?
I'm making a todo list and I have li and button tags added dynamically when adding a new list item. The button is an x which is supposed to remove the list item. I have tried several things but can't figure out how to make an eventListener for each individual x button and remove the corresponding list item when it is clicked.
The renderTodos function is where all of the dynamically added content is created. I have a data-index set to each button in which I was trying to use to access each button to attach an eventListener on each dynamic button, but I wasn't sure how to implement that. From what I have read there should be a way to do this using the currentTarget or target of the event but I don't understand how that works.
var input = document.querySelector('input[name=todoItem]'),
btnAdd = document.querySelector('button[name=add]'),
btnClear = document.querySelector('button[name=clear]'),
list = document.querySelector('.todo'),
storeList = [];
function renderTodos(){
var el = document.createElement('li'),
x = document.createElement('button');
listLength = storeList.length;
//Set text for remove button
x.innerHTML = 'x';
for(var i = 0; i < listLength; i++){
el.innerHTML = storeList[i];
list.appendChild(el);
x.setAttribute('data-index', i);
el.appendChild(x);
}
// check for correct data-index property on x button
}
function addTodos(){
storeList.push(input.value);
// Check that input is getting pushed to list array
console.log(storeList);
renderTodos();
}
function clearList(){
// make list empty
list.innerHTML = '';
storeList.splice(0, storeList.length);
//render empty list
renderTodos();
//Check that list array is empty
console.log(storeList);
}
btnAdd.addEventListener('click', addTodos);
btnClear.addEventListener('click', clearList);
Everything else on the list works so far I just can't figure out how to implement this eventListener.
One simple example can be
//a click hadler is added to #mylist which is already present in the dom
document.querySelector('#mylist').addEventListener('click', function(e) {
//assuming that the the `x` is in a span and it is the only span in the `li` we check for that, we can improve this check more to make sure we have actually clicked on the delete button
if (e.target.tagName == 'SPAN') {
//if so then since we know the structure we can delete the parent node of the target which is the span element
e.target.parentNode.parentNode.removeChild(e.target.parentNode);
}
}, false);
//kindly forgive the use of jQuery here
for (var i = 0; i < 10; i++) {
$('<li />', {
text: i
}).append('<span class="x">X</span>').appendTo('#mylist');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul id="mylist"></ul>
This is a very basic implementation of event delegation, where the actual event is bound to an ancestor element but then we use the actual event target to determine whether to act on it. We can improve the if condition to test for an class for any other attribute!!!
You can add a listener to each button using something like:
x.innerHTML = '';
x.onclick = function(){
var node = this.parentNode;
node.parentNode.removeChild(node);
};
Or you can keep the renderTodos code as it is and delegate the remove to the parent UL:
// Add the listener
list.addEventListener('click', removeItem);
// The listener function
function removeItem(event) {
var node = event.target;
// Check that the click came from an X button
// better to check against a class name though
if (node.tagName &&
node.tagName.toLowerCase() == 'button' &&
node.innerHTML == 'x') {
node = node.parentNode;
node.parentNode.removeChild(node);
}
}
basically what you want to do is add an event on the parent container and wait for the event to bubble up and identify if the event originating is from your x mark and if it is then trigger the callback function.. This is the concept I think most of the libraries use..
Or use a library like jQuery, why solve a problem that has already been solved by others.
Working on a project where I need to manually fill in input fields and textareas on various random websites. So far I've been doing "element.value = 'new value'" alongside "element.innerHTML = 'new value'", but for some websites there seem to be event listeners that aren't getting called when I do this.
So I figured I'd better call these manually, and added "element.onchange()" and a bunch of others (onkeypress, onkeydown, onkeyup), and also tried passing in the element into the function "element.onchange(element)". But neither of these seem to work for many websites.
As an example, go to http://www.facebook.com (logged out) and run:
javascript:var elements = document.getElementsByClassName('inputtext'); for(var i = 0; i < elements.length; i++) { var element = elements[i]; element.value = 'New Test Value'; element.innerHTML = 'New Test Value'; element.onkeypress; };
You should see all input boxes change value to "New Test Value", but the placeholder text is still in place (belongs to a different element). When you click on a input box on the page manually some function is getting called that removes this if there's text in the box.
So how do I make sure that any event listener attached to the element always gets called just as it does when we change value manually?
Hope this helps
var isCreatEvent = "createEvent" in document,
allEles = document.querySelectorAll('input'); // collect required elements.
for(var i = 0; i < allEles.length; i++){
var element = allEles[i];
element.onchange();
if (isCreatEvent) {
var evt = document.createEvent("HTMLEvents");
evt.initEvent("change", false, true);
element.dispatchEvent(evt);
}
else
element.fireEvent("onchange");
}