Hi Im trying to access the child nodes of a selected element, but the browser tells me that that object doesn't have a foreach function. What should I do for me to access the child elements. I dont want to use jquery instead I want to use native, for experiment purpose.
here is my code:
var el = document.querySelector('ol');
el.children.forEach(function(childEl) {
console.log(childEl);
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<ol contenteditable oninput="">
<li>press enter</li>
</ol>
</body>
</html>
Node.children is dom collection, not an real array so it doesn't have array methods like forEach(need to fix the case also).
So one commonly used solution is to call the array methods with the context as the html collection
var el = document.querySelector('ol');
[].forEach.call(el.children, function(childEl) {
console.log(childEl);
})
<ol contenteditable oninput="">
<li>press enter</li>
</ol>
Another way(similar) is to convert the collection to an array first(using Array.slice()) then call array methods on it
var el = document.querySelector('ol'),
array = [].slice.call(el.children);
array.forEach(function(childEl) {
console.log(childEl);
})
<ol contenteditable oninput="">
<li>press enter</li>
</ol>
Related
I am using jQuery replaceWith() method to replace some content from the html. Its working fine. But I want to change the data attribute value once replaceWith() has been done.
So basically I am getting this from my ajax response
UpdatedItem = '<li data-cart-key="XXX" data-item-name="Test" data-item-price="$111.00" data-item-key="XXX"><span class="cart-action-wrap"><a class="edit-cart-item" data-cart-item="XXX" data-cart-key="XXX" data-cart-action="edit">Edit</a><a class="remove-cart-item" data-cart-item="XXX" data-cart-key="XXX" data-cart-action="remove">Remove</a></span></li>';
Now I am using replaceWith() here like this
$( 'ul.custom-contents' ).find( 'li.updated' ).replaceWith( UpdatedItem );
Here I wanted to use methods like update data attribute value, remove class, add class after replaceWith() has been done.
So can someone tell me is there any way available to do this? Any help and suggestions would be really appreciable. Thanks
you can solve like this.
UpdatedItem =
'<li data-cart-key="" data-item-name="Test" data-item-price="$111.00" data-item-key="XXX">updated</li>';
divElement = document.createElement("div");
divElement.innerHTML = UpdatedItem;
element = divElement.firstElementChild;
$("ul.custom-contents").find("li.updated").replaceWith(element);
element.setAttribute("data-item-name", "myValue");
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<ul class="custom-contents">
<li class="updated">old</li>
<li class="">old</li>
<li class="">old</li>
</ul>
<script src="app.js"></script>
</body>
</html>
You can create a jQuery object inside replaceWith, do the operations and return it. Use .find() for nested elements:
$( 'ul.custom-contents' ).find( 'li.updated' ).replaceWith( fucntion(){
let obj = $(UpdatedItem)
obj.addClass("..")
obj.data("cart-key", "..")
obj.data("item-name", "..")
obj.removeClass("..")
//Find <a> with class "edit-cart-item"
obj.find("a.edit-cart-item").addClass(...)
obj.find("a.edit-cart-item").data("item-name", "..")
return obj;
});
I am trying to use the Have I Been Pwned? API to retrieve a list of breaches for a given email account.
I retrieve this list using the fetch() API. In the browser it looks like there is a connection to the HIBP website but the expected breaches are not visible.
I think this is a JSON problem because the API returns results without a root tree (?) (e.g. [breaches:{"Name"... - only the {"Name"}), so I think I'm making a mistake at the iteration step in the JS file. Also, I'm not calling the 'retrieve' function in the HTML file correctly because the browser throws an error: 'Uncaught ReferenceError: retrieve is not defined', but this is a side-issue (fetch('https://haveibeenpwned.com/api/v2/breachedaccount/test#example.com') doesn't work either).
This is my first week working with JS, fetch(), and JSON, so I consulted a couple of sources before asking this question (but I still can't figure it out, after a couple of days):
How to Use the JavaScript Fetch API to Get Data
fetch API
API methods for HaveIBeenPwnd.com (unofficial)
Where is the actual problem?
The index.html file:
<!DOCTYPE html>
<html lang=en>
<head>
<title>test</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex, nofollow">
</head>
<body id="top">
<header id="header">
<div class="content">
<h1 style="text-align: center">Put an email in this box</h1>
<input type="email" id="InputBox" value="" autocapitalize="off" spellcheck="false" />
<button type="submit" id="PwnedButton" onclick="retrieve">pwned?</button>
<ul id="results"></ul>
</div>
</header>
<script src="test.js"></script>
</body>
</html>
The test.js file (I know that JS is an interpreted language - so empty characters affect execution speed - but I made it more readable for this example):
function createNode(element) {
return document.createElement(element); // Create the type of element you pass in the parameters
}
function append(parent, el) {
return parent.appendChild(el); // Append the second parameter(element) to the first one
}
const account = document.getElementById('InputBox');
const PwnedButton = document.getElementById('PwnedButton');
const results = document.getElementById('results');
fetch('https://haveibeenpwned.com/api/v2/breachedaccount/' + account)
.then((resp) => resp.json()) // Transform the data into json
.then(function(retrieve) {
let breaches = retrieve.Name; // Get the results
return breaches.map(function(check) { // Map through the results and for each one run the code below
let span = createNode('span'); // Create the element we need (breach title)
span.innerHTML = `${breaches}`;
append(results, span);
})
})
.catch(function(error) {
console.log(JSON.stringify(error));
});
let breaches = retrieve.Name;
retrieve is not an object with a Name property.
It is an array containing multiple objects, each of which has a Name property.
You have to loop over it.
e.g.
retrieve.forEach( item => {
let breaches = retrieve.Name;
console.log(breaches);
});
breaches.map
… and the Name is a string, so you can't map it. You can only map an array (like the one you have in retrieve).
I have created working version of what are you possible going to implement, taking Name field from result. https://jsfiddle.net/vhnzm1fu/1/ Please notice:
return retrieve.forEach(function(check) {
let span = createNode('span');
span.innerHTML = `${check.Name}<br/>`;
append(results, span);
})
This question already has answers here:
Why does jQuery or a DOM method such as getElementById not find the element?
(6 answers)
Closed 4 years ago.
I am a beginner in Javascript. I am doing some exercises and coming across the error listed above for the 'onclick'.
I have looked at other questions on this forum and it has not be helpful for me. I have looked over syntax numerous times in both my html and JS and can't find anything!
var item1;
var item2;
var item3;
document.getElementById("changeList").onclick = newList;
function newList() {
item1 = prompt("Enter a new first thing:");
item2 = prompt("Enter a new second thing:");
item3 = prompt("Enter a new third thing:");
updateList();
}
function updateList() {
document.getElementById("firstThing").innerHTML = item1;
document.getElementById("secondThing").innerHTML = item2;
document.getElementById("thirdThing").innerHTML = item3;
}
<html>
<head>
<meta charset="UTF-8">
<title>Javascript Practice</title>
<script src="main.js"></script>
</head>
<body>
<h1 id="myName">Angie</h1>
<hr>
<p id="aboutMe"><em>I am trying to learn this damn javascript and stick with it.</em></p>
<h2>Things I like</h2>
<p>Here are some of the things I like to do:</p>
<ul>
<li id=firstThing>Dance</li>
<li id=secondThing>Write</li>
<li id=thirdThing>Travel</li>
</ul>
<button id="changeList" type="button">Change Your List</button>
</body>
</html>
You can try placing your script tag at the bottom of the page as suggested by lealceldeiro or you can wait for the DOM to load fully before adding your event listener for onclick like so:
//Replace this line
document.getElementById("changeList").onclick = newList;
//With the following, this fires an event when the DOM has fully loaded
//This will ensure your element has been rendered into the DOM
document.addEventListener("DOMContentLoaded", function(event) {
document.getElementById("changeList").onclick = newList;
});
Try changing your html line to :
<button id="changeList" type="button" onclick = newList();>Change Your List</button>
and remove this line from your JS
document.getElementById("changeList").onclick = newList;
I am trying to make an extremely basic to do list. I have researched and looked at many examples to no avail. All I want to do is have the ability to click an item that has been added to my list and have it deleted. I am not sure how to access the value of what Is entered in my items, or how to manipulate those into a function.
function todoList() {
let item = document.getElementById('todoInput').value //pulling value from input box
let text = document.createTextNode(item) //turning input text into node
let newItem = document.createElement('li') //creates a list
newItem.appendChild(text) //appends task entered from input
document.getElementById('todoList').appendChild(newItem) //appends the entered task to the list
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<title>To do list</title>
</head>
<body>
<h1>To Do List</h1>
<form id="todoForm">
<input type="text" id="todoInput">
<button type="button" onclick="todoList()">Add Item</button>
</form>
<ul id="todoList"></ul>
<script src="app.js"></script>
</body>
</html>
Here is a likely course of actions. There are many ways you can do it, and here is one that is functional.
I have broken it down for you. I also renamed your add function to be a little more clear what it does:
<!DOCTYPE html>
<html>
<head>
<!-- <link rel="stylesheet" type="text/css" href="style.css"> -->
<title>To do list</title>
<!-- Put this in your style.css -->
<style>
.item {
color: blue;
}
</style>
</head>
<body>
<h1>To Do List</h1>
<form id="todoForm">
<input type="text" id="todoInput">
<button type="button" onclick="addItem()">Add Item</button>
</form>
<ul id="todoList"></ul>
<!-- <script src="app.js"></script> -->
</body>
</html>
<script>
function addItem(){
//get current number of todo Items (for creating the ID)
const currentNumberOfItems = document.querySelectorAll('.item').length
console.log(currentNumberOfItems)
console.log('Research:', document.querySelectorAll('.item'))
const item = document.getElementById('todoInput').value //pulling value from input box
const text = document.createTextNode(item) //turning input text into node
const newItem = document.createElement('li') //creates a list
newItem.id = currentNumberOfItems //give the new <li> an auto-incrementing id property
newItem.classList.add('item') //add the item class so we can search for it by class
//we didn't end up searching by class, but you can find every <li> on the page
//using console.log(document.querySelectorAll('.item'))
newItem.appendChild(text) //appends task entered from input
document.getElementById('todoList').appendChild(newItem) //appends the entered task to the list
const btn = document.createElement('button') // Create a <button> element
const t = document.createTextNode('Delete') // Create a text node
btn.appendChild(t) // Append the text to <button>
newItem.appendChild(btn) // Append <button> into the new <li>
//we are going to create an event listener on the button
//this takes 2 parameters
//first = event type (on click)
//second = callback function to run when the event is detected
btn.addEventListener('click', function(event) {
console.log(event.target.parentNode) //we want the element in which the button exists
console.log('Research:', event) //look at all the stuff in here!
deleteItem(event.target.parentNode) //run our delete function
})
}
//now that we have an event listener and know the parent
//we just have to find a way to delete the parent
//we can call the input anything, and it will be a DOM element (event.target.parentNode)
function deleteItem(parent) {
console.log(parent.id) //lets check the parent's id
//we can use element.removeChild() to ditch the todo item
//first, we have to get the <ul> somehow
const todoList = document.getElementById('todoList') //let's get the <ul> by ID
todoList.removeChild(parent) //cya later "parent that the button was inside of"
}
</script>
I tried to make this a snippet, but it seems the code editor crashes when you delete, so I will leave it like this.
Bonus
You will see I used const instead of let, because it does not allow re-assignment, which tells JavaScript and other coders that you do not plan to change that variable once it is set.
You can sample that by putting this in your JS file:
app.js
'use strict'
const test = 'cool'
test = 'not cool'
console.log(test)
Notice the behaviour now with let (swap the code for this):
'use strict'
let test = 'cool'
test = 'not cool'
console.log(test)
This some basics with "immutability" that you should research a bit when you want to do some reading. It means you dont have to worry quite as much with strange bugs when you accidently mutate some variable. const will get mad if you try.
More advanced, you can still re-assign properties on objects when using const:
const object = {
name: 'Bob Alice'
}
object.name = 'Not Bob Anymore'
When you use let, it tells yourself and other coders that you expect the value of the variable will likely change somewhere nearby in the code.
I recommend you try this out and if you ever encounter any issues, just Google it and you will quickly discover. Don't worry, nothing will blow up on you if you always use const "unless you cant". Issues will only occur in highly advanced code, with const vs. let vs. var.
I have a string which contains this text:
<!DOCTYPE html>
<html>
<head>
<title>ExtractDiv test</title>
</head>
<body>
<p>Apples and oranges</p>
<div id="main">
<ul style="list-style-type: upper-roman">
<li>Äpfel</li>
<li>Birnen</li>
</ul>
</div>
<p>Men and women</p>
</body>
</html>
Now I need a JavaScript function which gives me back a DOM element with a specific ID as a string from this text, for example:
function ExtractElementByIdFromString(HTMLString, IdString)
{
var ExtractedElement = ???(HTMLString, IdString);
return ExtractedElement;
}
So the RESULT of this function in this case would be:
<div id="main">
<ul style="list-style-type: upper-roman">
<li>Äpfel</li>
<li>Birnen</li>
</ul>
</div>
Is this possible?
You can parse an HTML string with the native DOMParser:
var str = "<!DOCTYPE……………" // your HTML string
var doc = new DOMParser().parseFromString(str, "text/html")
Then just use regular DOM methods:
console.log( doc.getElementById("main") )
Note that using a DOMParser is more efficient and safer than inserting the string somewhere in your document's innerHTML, because only the structure will be created — <script> elements won't be executed, images won't be loaded, CSS will no try to apply to it, no rendering will occur, etc.
You can create a temporary element, put the HTMLString as a content to it, then use querySelector to get an element with passed id. Something like this:
function ExtractElementByIdFromString(HTMLString, IdString) {
var result,
temp = document.createElement('div'); // Create a temporary element
temp.innerHTML = HTMLString; // Set the passed string as HTML to the temporary element
result = temp.querySelector('#' + IdString).outerHTML; // Find an element with the passed id
return result;
}
A working demo at jsFiddle.