I am developing a chat app, and my issue raises when I try to add new elements to a list of chat rooms, see them, and interact with them without reloading the page.
I am adding HTML elements to a list with JavaScript.
Then I try to querySelectorAll elements in the list.
The elements that were loaded from the server on page load can be selected.
But the newly created elements with JavaScript don't seem to get selected.
Here is how I try to select my elements and, when clicked, execute some code for each of them:
document.querySelectorAll('.select-room').forEach(p => {
p.onclick = () => { <my code here> })
The elements that are already on the list get selected just fine and my code executes alright.
But when I add a new element with JavaScript. Even though the HTML of it looks just the same as the HTML of other existing elements, including the class by which it gets selected, the result is I can only select those after reloading the page.
Is there a way I can listen for changes made to the DOM, so that after adding with JavaScript new elements with the same class, they will be selected like the others without having to reload the page?
Here is a Minimal, Complete, Reproducible Example of my problem:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>mcr problem</title>
<script>
document.addEventListener("DOMContentLoaded", () => {
// Clicking element in the list shows an alert.
document.querySelectorAll(".clickable").forEach(li => {
li.onclick = () => {alert("interaction!")};
});
// Clicking on button adds new element to the list
document.querySelector("#add-btn").onclick = () => {
newLi = document.createElement("li");
newLi.classList.add("clickable");
newLi.innerHTML = "New Item";
document.querySelector("#parent-list").append(newLi);
};
});
</script>
</head>
<body>
<h1>List of items</h1>
<button id="add-btn">Add</button>
<ul id="parent-list">
<li class="clickable" id="post-1">Item 1</li>
<li class="clickable" id="post-2">Item 2</li>
<li class="clickable" id="post-3">Item 3</li>
</ul>
</body>
</html>
Reasons why alert was not getting called DOMContentLoaded
This event triggers when the DOM tree forms i.e. the script is loading. Scripts start to run before all the resources like images, CSS, and JavaScript loads. You can attach this event either to the window or the document objects
and at that time the query selector has only 3 node of class .clickable so it apply only on those 3 elements.
In javascript DOMNodeInserted
It fires when the script inserts a new node in the DOM tree using appendChild(), replaceChild(), insertBefore(), etc.
document.addEventListener("DOMContentLoaded", () => {
document.querySelectorAll(".clickable").forEach((li) => {
li.onclick = () => commonAlertMethod();
});
// Clicking on button adds new elemnt to the list
document.querySelector("#add-btn").onclick = () => {
newLi = document.createElement("li");
newLi.classList.add("clickable");
newLi.innerHTML = "New Item";
document.querySelector("#parent-list").append(newLi);
};
});
document.addEventListener("DOMNodeInserted", () => {
// Clicking element in the list shows an alert.
document.querySelectorAll(".clickable").forEach((li) => {
li.onclick = () => commonAlertMethod();
});
});
function commonAlertMethod() {
alert("interaction!");
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>List of items</h1>
<button id="add-btn">Add</button>
<ul id="parent-list">
<li class="clickable" id="post-1">Item 1</li>
<li class="clickable" id="post-2">Item 2</li>
<li class="clickable" id="post-3">Item 3</li>
</ul>
</body>
</html>
Related
So I've got this little chrome extension project and I'm trying to figure out how to find the first "ul" element on the page that comes after an "h2" element that contains a particular word.
Example of what the web page would look like...
<div>
<h2>Foo</h2> // find the first <h2> tag containing "Foo"
<ul></ul> // find the first <ul> tag that comes after the <h2>
</div>
However the nature of varying page code means that it may looks more like this...
<h2>Foo</h2> // find the first <h2> tag containing "Foo"
<div>
<ul></ul> // find the first <ul> tag that comes after the <h2>
</div>
Or even...
<div>
<h2>Foo</h2> // find the first <h2> tag containing "Foo"
</div>
<div>
<ul></ul> // find the first <ul> tag that comes after the <h2>
</div>
I can get the "h2" element containing "foo" by...
let hTags = document.querySelectorAll("h2");
let hTag;
for (var i = 0; i < hTags.length; i++) {
if (/foo/i.test(hTags[i].textContent)) {
hTag = hTags[i];
break;
}
}
But that is where I'm stuck, I can't figure out how to search the rest of the DOM that follows the found "h2" tag. Sibling selectors won't work as the "h2" and the "ul" may not be within the same element.
Also being a chrome extension rules out using anything like jQuery.
Does anyone know if this is possible? Any thoughts would be very much appreciated!
This should do the trick:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div>
<h2>Foo</h2>
</div>
<div>
<ul></ul>
</div>
<script>
const regex = new RegExp('foo', 'i');
const foundElements = [...document.querySelectorAll('* H2, UL')];
const firstUL = foundElements
.slice(1)
.find(
(el, i) => el.tagName === 'UL' && foundElements[i].tagName === 'H2' && regex.test(foundElements[i].innerText)
);
console.log(firstUL);
</script>
</body>
</html>
This question already has answers here:
What do querySelectorAll and getElementsBy* methods return?
(12 answers)
Closed 2 years ago.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="text" class="input">
<ul class="list">
<li class="lies" name="lies" >Adem</li>
<li class="lies" name="lies" >Adem1</li>
<li class="lies" name="lies" >Adem2</li>
<li class="lies" name="lies" >Adem3</li>
<li class="lies" name="lies" >Adem4</li>
</ul>
<button class="button">Add name</button>
<script>
const listChild = document.querySelectorAll('.lies');
listChild.addEventListener('click', () => {
listChild.parentNode.removeChild('listChild');
});
</script>
</body>
</html>
(l know only HTML, css , javascript. so don't try to answer with jquery. l won't get it)
l want when l click on li*s to disappear. but code doesn't work properly.
Is this was you're trying to do?
const listChildren = document.querySelectorAll('.lies');
listChildren.forEach(function(listChild){
listChild.addEventListener('click',function(event){
event.target.parentNode.removeChild(event.target);
});
});
<input type="text" class="input">
<ul class="list">
<li class="lies" name="lies" >Adem</li>
<li class="lies" name="lies" >Adem1</li>
<li class="lies" name="lies" >Adem2</li>
<li class="lies" name="lies" >Adem3</li>
<li class="lies" name="lies" >Adem4</li>
</ul>
<button class="button">Add name</button>
1) the querySelectorAll function returns a NodeList of matching DOM elements. Note that a node list is like an array in that you can iterate over it using forEach but it is not an array.
2) The removeChild function takes a dom element as a parameter. What you have is a string that happens to have the same contents as your variable name.
Although as I mentioned you can iterate over a NodeList with a forEach I'll just use an old-school for loop.
Note that I also added a click handler for your button to append the text in the text box as a new name at the end of the list.
const listChildren = document.querySelectorAll('.lies');
for (let i = 0; i < listChildren.length; i++) {
let item = listChildren[i];
item.addEventListener('click', () => {
item.parentNode.removeChild(item);
});
}
let itemList = document.querySelector('.list');
let addNameBtn = document.querySelector('button');
addNameBtn.addEventListener('click', () => {
let newNameNode = document.querySelector('.input');
let newName = newNameNode.value;
// only continue if there is text in the input box (i.e. don't allow adding blank names)
if(newName && newName != ''){
// creast ethe new li dom element to hold the name and set the class and name
var li=document.createElement('li');
li.innerHTML = newName
li.className = "lies";
li.name = "lies";
// register click handler
li.addEventListener('click', () => {
li.parentNode.removeChild(li);
});
//Append the new name to the list.
itemList.appendChild(li);
// blank out the input to allow fo rentry of the next name
newNameNode.value = "";
}
});
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="text" class="input">
<ul class="list">
<li class="lies" name="lies" >Adem</li>
<li class="lies" name="lies" >Adem1</li>
<li class="lies" name="lies" >Adem2</li>
<li class="lies" name="lies" >Adem3</li>
<li class="lies" name="lies" >Adem4</li>
</ul>
<button class="button">Add name</button>
</body>
</html>
I just started to learn JavaScript/jQuery, and I made a little test website to practice coding.
In one of the tests I made, there is a list that says Milk and Eggs. There is an input field and a button, which you can type something, click the button, and add it to the list. I then added an option where if you click on one of the list items, it removes it. This works, but only on the preset Milk and Eggs items, not any items that you add yourself.
I think it's because the code wasn't loaded for the newly added items, but I'm not sure. Can someone help?
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Practice 3</title>
<link href="index.css" rel="stylesheet" type="text/css">
<script src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
</head>
<body>
<div class="Title" align="center">
<h1>Hello</h1>
<p>This website will use JavaScript to create interactive elements.</p>
</div>
<div class="1">
<h3>Test 1</h3>
<ul id="list">
<li>Milk</li>
<li>Eggs</li>
</ul>
<input id="textbox">
<button id="add">Add to list</button>
</div>
<script>
$('#add').click(function() {
var listvalue = $('#textbox').val();
$("#textbox").val("");
$('ul').append('<li>' + listvalue + '</li>');
});
$('#textbox').keypress(function(event) {
if(event.which === 13) {
var listvalue = $('#textbox').val();
$('#textbox').val("");
$('ul').append('<li>' + listvalue + '</li>');
}
});
$('li').click(function(e) {
$(e.target).remove();
});
</script>
</body>
</html>
Use event delegation
$('#list').on('click', 'li', function(e) {
$(this).remove();
});
Example
You can use on to bind the click even to the document, then specify a selector to specify that it should only trigger for li elements:
$(document).on('click', 'li', function (e) {
$(this).remove();
});
This will still work with newly-added li elements because the event-handler itself is bound to the document itself, not the individual elements. It simply performs a runtime check to ensure that the dispatched event matches the provided selector.
Answered by Gone Coding on stackoverflow:
https://stackoverflow.com/a/34857252/7074256
And here is example how to do it with jquery:
function moveItems(origin, dest) {
$(origin).closest("li").appendTo(dest);
}
$(document).on('click', '.add', function () {
moveItems(this, '#listTwo');
});
$(document).on('click', '.remove', function () {
moveItems(this, '#listOne');
});
JSFiddle: http://jsfiddle.net/TrueBlueAussie/r7j3odyy/4/
I've just copied the demo code from the site http://www.jstree.com/ of jstree and tried to add the option of new node. There is no error but it don't add new node.
This is my code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>jsTree test</title>
<!-- 2 load the theme CSS file -->
<link rel="stylesheet" href="dist/themes/default/style.min.css" />
</head>
<body>
<!-- 3 setup a container element -->
<div id="jstree">
<!-- in this example the tree is populated from inline HTML -->
<ul>
<li>Root node 1
<ul>
<li id="child_node_1">Child node 1</li>
<li>Child node 2</li>
</ul>
</li>
<li>Root node 2</li>
</ul>
</div>
<button>demo button</button>
<!-- 4 include the jQuery library -->
<script src="dist/libs/jquery.js"></script>
<!-- 5 include the minified jstree source -->
<script src="dist/jstree.min.js"></script>
<script>
$(function () {
// 6 create an instance when the DOM is ready
$('#jstree').jstree();
// 7 bind to events triggered on the tree
$('#jstree').on("changed.jstree", function (e, data) {
console.log(data.selected);
});
// 8 interact with the tree - either way is OK
$('button').on('click', function () {
$('#jstree').jstree(true).select_node('child_node_1');
//$('#jstree').jstree().create_node(null,'AAA','last'); first option
//$("#jstree").jstree("create_node", $("j1_3"), "after", { "data": "Hello");
$('#jstree').jstree('select_node', 'child_node_1');
$.jstree.reference('#jstree').select_node('child_node_1');
});
});
</script>
</body>
</html>
Look at remarked lines. No error but don't add rhe new node. Does somebody have any idea?
try this..
$('#jstree').jstree("create_node", "parent_id", function(e,data){
console.log('hi', data);
});
I have 5X5 text box with letters that randomly change every few seconds. I figured out how to make the box selectable. Now I want to be able to retrieve the letter that's appearing within the box at the time that I click. I'm new to coding, but after researching, I thought I could combine the .click function with the .text() function. I add a tag and tried to print the clicked letter within it. It's not working. I'm I using the .text() function incorrectly? I haven't used it before so I'm not sure.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>LetterTouch</title>
</head>
<link rel = "stylesheet" type="text/css" href="gameboard.css">
<!-- <link href="scripts/jquery-ui-1.10.4.custom.css" rel="stylesheet" type="text/css"/>-->
<script type="text/javascript" src="scripts/jquery-1.10.2.js"></script>
<script type="text/javascript" src="scripts/jquery-ui-1.10.4.custom.js"></script>
<script type="text/javascript">
$("document").ready(function() {
$("#squares").selectable();
});
var nIntervId;
var letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
function changeLetters() {
nIntervId = setInterval(boardGen, 1500);
}
function boardGen() {
$('li').each(function (i, e) {
$(e).text(letters.charAt(Math.floor(Math.random() * letters.length)));
})
}
$( "li" ).click(function() {
$( this ).text();
$( "p" ).html( );
});
changeLetters();
</script>
<body>
<ol id="squares">
<li class="A1"></li>
<li class="A2"></li>
<li class="A3"></li>
<li class="A4"></li>
<li class="A5"></li>
<li class="B1"></li>
<li class="B2"></li>
<li class="B3"></li>
<li class="B4"></li>
<li class="B5"></li>
<li class="C1"></li>
<li class="C2"></li>
<li class="C3"></li>
<li class="C4"></li>
<li class="C5"></li>
<li class="D1"></li>
<li class="D2"></li>
<li class="D3"></li>
<li class="D4"></li>
<li class="D5"></li>
<p> H </p>
</body>
</html>
Might be this is what you are trying to do http://jsfiddle.net/jogesh_pi/X24s9/
$("document").ready(function() {
$("#squares").selectable();
$( "#squares" ).on('click', 'li', function() {
var txt = $( this ).text();
$("p").html(txt);
});
});
Just pass the text of that clicked li element as the parameter of html() function gonna be run on behalf of the p tag.
Try,
$("#squares li").click(function() {
$("p").html($(this).text());
});
And also your html seems invalid, please try to close that <ol> tag
Since you're inserting the characters inside the li, you will want to use .text() to pick them up.
e.g.
$( "li" ).click(function() {
$( "p" ).html($(this).text());
});
what this does is that I took the html content of the li - referenced by $(this).text(), and assigned that to be the content of the p element. How .html() works is that placing a string parameter in it assigns that to its html content.
Simply use the .text() property.
$("p").html($(this).text());