How to get text from h3 with native js? - javascript

I have some h3 elements with the same class. I need to get text from h3 when i click on one of the elements.
document.querySelector(`.block__item__name`).onclick = function() {
let value = this.textContent;
console.log(value);
};
This code works with first h3 only. How can i fix it?

const content = document.getElementsByClassName("titel");
for (let i = 0; i < content.length; i++) {
content[i].addEventListener("click", function () {
let value = this.textContent;
console.log(value);
});
}
You can try it out here: https://jsitor.com/EKnmSAr5J

Per the documentation, querySelector gives you the first result for your query. If you want all results, use querySelectorAll
document.querySelectorAll(`.block__item__name`)forEach(item => {
item.onclick = function() {
let value = this.textContent;
console.log(value);
};
});

Related

Cannot append comparison value to DOM using javascript

The following function checks a form submission value against a data set. Currently, I am able to return a match using console.log. My question is, given that the function is working correctly in terms of comparison, how can I append the result to the body of my page? I attempted it with the following but could not get it to work:
function lookForMatches(){
const slugName = `${slugData.slug()}`;
for (var i = 0; i < globalArticles.length; i++) {
if(slugName === globalArticles[i]["slug"]){
const showMatches = document.createElement('div')
showMatches.innerHTML(`<p>${globalArticles[i]["slug"]}<p>`);
document.getElementById("slugResults").appendChild(showMatches);
}
else {
console.log("No Matches")
}
}
}
Any help would be much appreciated!
As others have mentioned, innerHTML is a property, not a function:
The Element property innerHTML gets or sets the HTML or XML markup contained within the element.
const content = element.innerHTML;
element.innerHTML = htmlString;
In your case, your code should look like this:
function lookForMatches() {
const slugName = `${slugData.slug()}`;
for (var i = 0; i < globalArticles.length; i++) {
if (slugName === globalArticles[i]["slug"]) {
const showMatches = document.createElement("div");
// Set's the inner HTML
showMatches.innerHTML = `<p>${globalArticles[i]["slug"]}</p>`;
document.getElementById("slugResults").appendChild(showMatches);
} else {
console.log("No Matches");
}
}
}

Iterating over a nodelist, getting the length of a value of a node item

I am trying to dynamically grab ZIPcodes and validate them when the length is 5.
I used querySelectorAll to grab the Zipcode fields on the page, as well as a few other fields I will use after validating.
I iterate over the nodelist and pass it to another function, where the eventlistener kicks off if the value is the correct length.
function GetZipCodeDetails() {
var zipId = document.querySelectorAll("[id*='ZipCode']");
var countyId = document.querySelectorAll("[id*='CountyId']");
var stateId = document.querySelectorAll("[id*='StateId']");
var phoneId = document.querySelectorAll("[id*='PhoneNumber']");
for (var i = 0; i < zipId.length; i++) {
if (zipId[i].length = 5)
AssortedZipCodeFunctions(zipId[i], countyId[i], stateId[i], phoneId[i]);
}
}
function AssortedZipCodeFunctions(zipId, countyId, stateId, phoneId) {
//Runs auto-county/state function only when zipcode field is completed
document.addEventListener("keyup", (e) => {
if (zipId.value.length == 5) {
GetCountyAndStateFromIds(zipId, countyId, stateId, phoneId);
} });
}
The code works perfectly for me as it is listed above; I am just trying to move the second function into the first function, but I can't figure out how. I am just stuck on how come I can't do the following:
function GetZipCodeDetails() {
var zipId = document.querySelectorAll("[id*='ZipCode']");
var countyId = document.querySelectorAll("[id*='CountyId']");
var stateId = document.querySelectorAll("[id*='StateId']");
var phoneId = document.querySelectorAll("[id*='PhoneNumber']");
for (var i = 0; i < zipId.length; i++) {
document.addEventListener("keyup", (e) => {
if (zipId[i].value.length == 5) {
GetCountyAndStateFromIds(zipId[i], countyId[i], stateId[i], phoneId[i]);
}
});
}
}
The above gives: "TypeError: Cannot read property 'value' of undefined
at HTMLDocument."
I have figured out that the for loop is calling the second function, instead of waiting until the Zipcode value is 5... so all that happened is I passed it to another function? Or maybe I am stuck on how to get the length of the value of a node item? Please help.
In your event listener you are adding it to the document instead of each element separately
for (var i = 0; i < zipId.length; i++) {
zipId[I].addEventListener("keyup", (e) => {
if (zipId[i].value.length == 5) {
GetCountyAndStateFromIds(zipId[i], countyId[i], stateId[i], phoneId[i]);
}
});
}

Calling object methods in javascript from html oninput() event

In javascript I have a list of objects of the same class.
Every object has the same variables and methods.
For each object that is added to the list, an input field is added in the html code.
Now, when the value of an input field is changed (<input oninput=...>)
I want to call the inputModified()method of the exact object in the list that was added to the list along with the input field.
How would you achieve this?
Also, if an object is removed from the list, than the html code that was added for that object is removed as well.
Is an incremental id the only way?
Also, please note that I can not use jquery or anything similar. Thanks!
The best way is not to use <input oninput=...> at all. Use modern event handling. Then you either attach a handler that closes over the entry in the list, or you include the position in the list on the element and use a delegated input handler on the container these inputs are in to figure out which entry on the list to update.
Here's an example of that first option, closing over the entry in the list:
function addToDOM(entry) {
const input = document.createElement("input");
input.type = "text";
input.value = entry.value;
// The event handler closes over `input` and `entry`
input.addEventListener("input", function() {
entry.value = input.value;
});
return input;
}
const list = [];
const container = document.getElementById("container");
for (let n = 0; n < 10; ++n) {
const entry = {
value: `Value ${n + 1}`
};
container.appendChild(addToDOM(entry));
list.push(entry);
}
// Adding another later
setTimeout(() => {
const entry = {
value: "Added later"
};
container.appendChild(addToDOM(entry));
list.push(entry);
}, 800);
document.getElementById("btnShowAll").addEventListener("click", function() {
list.forEach(({value}, index) => {
console.log(`[${index}].value = ${value}`);
});
});
<input type="button" id="btnShowAll" value="Show All">
<div id="container"></div>
Here's an example of the second option with a single delegated handler. Note, though, that if you modify the list, the index we're storing as a data-* attribute gets out of date:
function addToDOM(entry, index) {
const input = document.createElement("input");
input.type = "text";
input.value = entry.value;
input.setAttribute("data-index", index);
return input;
}
const list = [];
const container = document.getElementById("container");
container.addEventListener("input", function(e) {
const input = e.target;
const index = +input.getAttribute("data-index");
list[index].value = input.value;
});
for (let n = 0; n < 10; ++n) {
const entry = {
value: `Value ${n + 1}`
};
container.appendChild(addToDOM(entry, list.length));
list.push(entry);
}
// Adding another later
setTimeout(() => {
const entry = {
value: "Added later"
};
container.appendChild(addToDOM(entry, list.length));
list.push(entry);
}, 800);
document.getElementById("btnShowAll").addEventListener("click", function() {
list.forEach(({value}, index) => {
console.log(`[${index}].value = ${value}`);
});
});
<input type="button" id="btnShowAll" value="Show All">
<div id="container"></div>

getElementById check multiple conditions

I am trying to build a function that checks if all fields are populated, if populated then show div if not hide.
I can get this to work on one fields however i have then tried two ways of checking multiple.
first
if first condition met I then ran other condition checking second field nested inside the first... this done not work.
second
I passed in an array of ID's rather than a single... this did not work either..
I am left with a working function that only works if first filed is populated can anyone think of a solution to this or maybe i passed in my array incorrectly.
My code
var myVar = setInterval(myTimer, 10);
function myTimer() {
if(!document.getElementById('Email').value) { // I need this to pass if multiple id's
var divsToHide = document.getElementsByClassName("somediv"); //divsToHide is an array
for(var i = 0; i < divsToHide.length; i++){
divsToHide[i].style.visibility = "hidden"; // or
divsToHide[i].style.display = "none"; // depending on what you're doing
}
}
else {
var divsToHide = document.getElementsByClassName("somediv"); //divsToHide is an array
for(var i = 0; i < divsToHide.length; i++){
divsToHide[i].style.visibility = "visible"; // or
divsToHide[i].style.display = "block"; // depending on what you're doing
}
}
}
Make it so your function takes an argument of the element ID and the class Name you need to check for.
Also, never use .getElementsByClassName() (read here for why). Instead, use .querySelectorAll().
And, you can use the modern .forEach() API of arrays and node lists (not in IE though), which is simpler than managing traditional for loops with indexes.
Lastly, use pre-made CSS classes instead of inline styling.
// You just need to pass the ID and Class to the following line
var myVar = setInterval(function(){ myTimer([id here],[class here]) }, 10);
function myTimer(id, class) {
// Set up these references just once and the rest of the code
// will be easier to read
var elem = document.getElementById(id);
var divsToHide = document.querySelectorAll("." + class);
// Instead of negative logic, reverse the if branches
if(elem.value) {
divsToHide.forEach(function(){
this.classList.remove("hidden"); // Much simpler than inline styling
});
} else {
divsToHide.forEach(function(){
this.classList.add("hidden");
});
}
/* Use pre-made CSS classes instead of inline styling */
.hidden { display:none; }
If you have an array of the IDs such as
let idArray = ['foo', 'bar', 'baz']
You can iterate through an array using a for loop
for (i = 0; i > idArray.length; i++) {
if (!document.getElementById(idArray[i]).value) {
// your hide logic
} else {
// your show logic
}
}
You can create a const of all elements that need to validate. For example,
const elementIdsToBeValidated = ['name', 'email'];
You can also create validator functions that returns true and false based on input,
const nameValidator = (val) => !!val;
const emailValidator = (email) => !!email;
const validators = [nameValidator, emailValidator];
Then you can run your timer function,
var myVar = setInterval(myTimer(['name', 'email']), 10);
function myTimer(ids) {
ids.forEach(id => {
const el = document.getElementById(id);
const val = el.value;
const divEl = document.getElementById('error');
const valid = validators.reduce((acc, validator) => validator(val), false);
if(valid) {
divEl.style.display = 'none';
} else {
divEl.style.display = 'block';
}
});
}
You can look at this stackBlitz example,
https://stackblitz.com/edit/js-ie7ljf

Trouble with functions and local storage

This code originally took input.value and added it to the page. I added local storage to this project and the code is already written but I’m having a hard time displaying the input to the page from localStorage. The input is stored in local storage as objects in an array. I wrote a for loop to loop through those values and pass them to functions that builds the element and appends it to the li and later appends to the ul. It’s not displaying on the page and I’m not getting any errors in the console. I'm not sure where to turn so heres my code:
function fetchInvite() {
const rsvpInvite = JSON.parse(localStorage.getItem("Invitees"));
const rsvpList = document.getElementById('invitedList');
for(var i = 0; i < rsvpInvite.length; i++) {
const name = rsvpInvite[i].name;
const confirm = rsvpInvite[i].confirmed;
createLI(name, confirm);
function createLI(name, confirm) {
const li = document.createElement('li');
function createElement(elementName, property, value) {
const element = document.createElement(elementName);
element[property] = value;
return element;
}
function appendToLI (elementName, property, value) {
const element = createElement(elementName, property, value);
li.appendChild(element);
return element;
}
appendToLI('span', 'textContent', name);
appendToLI('label', 'textContent', confirm)
.appendChild(createElement('input', 'type', 'checkbox'));
appendToLI('button', 'textContent', 'edit');
appendToLI('button', 'textContent', 'remove');
return li;
}
}
}
The full project is available here: https://github.com/tianniNakiMyers/RSVP_TeamTreeHouse/blob/master/app.js
The problem with your code is that you probably never called fetchInvite.
Apart from that, here is a refactoring of your code:
function elt(parent, tag, text) { // create element of tagname tag and append it to a parent (if provided) then set its textContent to text and return it
var el = document.createElement(tag);
if(parent) {
parent.appendChild(el);
}
el.textContent = text;
return el;
}
function fetchInvite() {
const rsvpInvite = JSON.parse(localStorage.getItem("Invitees"));
const rsvpList = document.getElementById('invitedList');
for(var i = 0; i < rsvpInvite.length; i++) {
const name = rsvpInvite[i].name;
const confirm = rsvpInvite[i].confirmed;
const li = elt(rsvpList, 'li', ''); // create an li element with empty text and append it to rsvpList
elt(li, 'span', name); // create a span whose text is name and append it to li
elt(elt(li, 'label', confirm), 'input', '').type = 'checkbox'; // create an input append it to a label element that contain the text confirm and that is appended to li, then set type of input to 'checkbox'
elt(li, 'button', 'edit'); // ...
elt(li, 'button', 'remove');
}
}
fetchInvite(); // don't forget to call it

Categories