I try to get text from a site, using javascript and textContent
i use this code
var markets=document.getElementsByClassName('sip-MarketGroup ')
for (var i=0;i<markets.length;i++){
try {
console.log(markets[i].textContent);
} catch (error) {
console.error(error);
}
}
a part of html into the site is this below
<div class="sip-MarketGroup">
<div class="sip-MarketGroupButton sip-MarketGroup_Open ">
<div class="sip-MarketGroupButton_Text " style="">Fulltime Result</div>
<div class="sip-MarketGroupButton_FavouriteButton sip-FavouriteButton ">
<div class="sip-FavouriteButton_SVG "> </div>
</div>
</div>
<div class="gl-MarketGroup_Wrapper ">
<div class="gl-MarketGroupContainer ">
<div class="gl-Market gl-Market_General gl-Market_General-topborder gl-Market_General-pwidth100 ">
<div class="gl-Participant gl-Participant_General gl-Market_General-cn3 ">
<span class="gl-Participant_Name">QPR</span>
<span class="gl-Participant_Odds">12.00</span>
</div>
<div class="gl-Participant gl-Participant_General gl-Market_General-cn3 ">
<span class="gl-Participant_Name">Draw</span>
<span class="gl-Participant_Odds">4.00</span>
</div>
<div class="gl-Participant gl-Participant_General gl-Market_General-cn3 ">
<span class="gl-Participant_Name">Bournemouth</span>
<span class="gl-Participant_Odds">1.36</span>
</div>
</div>
</div>
</div>
</div>
and i get
Fulltime ResultQPR12.00Draw4.00Bournemouth1.36
without spaces, how can i get this text but seperated with ";" like this
Fulltime Result;QPR 12.00;Draw 4.00;Bournemouth 1.36;
Why don't you use the method "innerText" instead?
And you can do the following:
var markets=document.getElementsByClassName('sip-MarketGroup ')
for (var i = 0; i < markets.length; i++) {
try {
console.log(markets[i].innerText.split('\n').join(';'));
} catch (error) {
console.error(error);
}
}
But you can always remove the .join(';') and just use the array to do whatever you need :) Maybe even string interpolation!
Give me a heads up if you liked my answer!
Happy New Year!
Pedro
Related
im very new to javascript and probably thats a silly question. What I am trying to achieve is to loop through rows of a "table", get the innerHTML of specific child nodes and multiply them together.
The html looks like this:
<div class="parent">
...
<div class="countChild">
<div class="container">
<span class="count">5</span>
</div>
</div>
<div class="valueChild">
<span class="value">30</span>
</div>
...
</div>
<div class="parent">
...
<div class="countChild">
<div class="container">
<span class="count">2</span>
</div>
</div>
<div class="valueChild">
<span class="value">30</span>
</div>
...
</div>
To be specific: I want to get both the values inside the'countChild' and the 'valueChild'. In this example those are 5 and 30 for the first row and for the second row its 2 and 30. Then perform a muiltiplication.
What I tried to do is to get all the parent nodes and then iterating through them to get the child nodes.
const parents = document.getElementsByClassName('parent');
for(var row in parents) {
var count = row.getElementsByClassName('countChild').lastChild.innerHTML;
var value = row.getElementsByClassName('valueChild').lastChild.innerHTML;
....
}
However the debugger already throws an error when im trying to get the childs. The error message is row.getElemenstByClassName is not a function. I guess the collection cannot be used like this and my understanding of how to use js to get information from the document is wrong.
Edit: This is what the tree looks like
<div class="listing-entry">
<div class="value-container d-none d-md-flex justify-content-end">
<div class="d-flex flex-column">
<div class="d-flex align-items-center justify-content-end">
<span class="font-weight-bold color-primary small text-right text-nowrap">30</span>
</div>
</div>
</div>
<div class="count-container d-none d-md-flex justify-content-end mr-3">
<span class="item-count small text-right">5</span>
</div>
</div>
You should access parents like an array (not really array but you can cast it to one). Btw, I encourage you to use querySelectorAll and querySelector instead of getElementsByClassName
const parents = document.querySelectorAll(".parent")
parents.forEach(function(row) {
var countChild = row.querySelector(".countChild")
var valueChild = row.querySelector(".valueChild")
var count = countChild ? countChild.innerText : 0
var value = valueChild ? valueChild.innerText : 0
console.log(count, value, count * value)
})
<div class="parent">
...
<div class="countChild">
<div class="container">
<span class="count">5</span>
</div>
</div>
<div class="valueChild">
<span class="value">30</span>
</div>
...
</div>
<div class="parent">
...
<div class="countChild">
<div class="container">
<span class="count">2</span>
</div>
</div>
<div class="valueChild">
<span class="value">30</span>
</div>
...
</div>
Edit: I'm using querySelector instead of getElementsByClassName, and checking if child exists before accessing its innerText property.
Edit: here's a function to get all text nodes under a specific node. Then you can combine them and trim the result to get the value you want.
function textNodesUnder(node) {
var all = [];
for (node = node.firstChild; node; node = node.nextSibling) {
if (node.nodeType == 3) {
all.push(node);
} else {
all = all.concat(this.textNodesUnder(node));
}
}
return all;
}
var nodes = textNodesUnder(document.querySelector(".listing-entry"))
var texts = nodes.map(item => item.nodeValue.trim())
console.log(texts)
<div class="listing-entry">
<div class="value-container d-none d-md-flex justify-content-end">
<div class="d-flex flex-column">
<div class="d-flex align-items-center justify-content-end">
<span class="font-weight-bold color-primary small text-right text-nowrap">30</span>
</div>
</div>
</div>
<div class="count-container d-none d-md-flex justify-content-end mr-3">
<span class="item-count small text-right">5</span>
</div>
</div>
again, probably a terrible title - but what I'm trying to do is to make a simple search feature on my website. You click a nav button, which updates the search bar, whi in turn triggers an onchange event to update the current appended list.
function update() {
var list = $("#comic__modern-list");
list.empty();
$.each(Object.keys(comics), function() {
var currentObject = comics[this];
var filter = comics[this].type;
var publisher = comics[this].publisher;
if (search == "") {
if(filter == "modern") {
list.append(`
<div class="comic__box">
<div class="comic__image-box">
<img src="${currentObject['data-item-image']}" alt="${currentObject['data-item-description']}" class="img-fluid">
<div class="comic__desc-wrap">
<div class="comic__desc">${currentObject['data-item-description']}, issue #${currentObject['issue']} (${currentObject['year']})</div>
</div>
</div>
<div style="text-align:center; margin-top: 1rem">
<button
class="btn btn-warning snipcart-add-item comic__button"
data-item-id="${currentObject['data-item-id']}"
data-item-price="${currentObject['data-item-price']}"
data-item-url="${currentObject['data-item-url']}"
data-item-description="${currentObject['data-item-description']}"
data-item-image="${currentObject['data-item-image']}"
data-item-name="${currentObject['data-item-name']}">
<div class="comic__desc-desk">£${currentObject['data-item-price']}<br>Add to cart</div><div class="comic__desc-mob">BUY <br> ${currentObject['data-item-description']}, Issue: ${currentObject['issue']} (${currentObject['year']})</div>
</button>
</div>
</div>
`)
}
} else if (search == publisher) {
list.append(`
<div class="comic__box">
<div class="comic__image-box">
<img src="${currentObject['data-item-image']}" alt="${currentObject['data-item-description']}" class="img-fluid">
<div class="comic__desc-wrap">
<div class="comic__desc">${currentObject['data-item-description']}, issue #${currentObject['issue']} (${currentObject['year']})</div>
</div>
</div>
<div style="text-align:center; margin-top: 1rem">
<button
class="btn btn-warning snipcart-add-item comic__button"
data-item-id="${currentObject['data-item-id']}"
data-item-price="${currentObject['data-item-price']}"
data-item-url="${currentObject['data-item-url']}"
data-item-description="${currentObject['data-item-description']}"
data-item-image="${currentObject['data-item-image']}"
data-item-name="${currentObject['data-item-name']}">
<div class="comic__desc-desk">£${currentObject['data-item-price']}<br>Add to cart</div><div class="comic__desc-mob">BUY <br> ${currentObject['data-item-description']}, Issue: ${currentObject['issue']} (${currentObject['year']})</div>
</button>
</div>
</div>
`)
}
});
}
The current list is generated by this, which works fine:
$.each(Object.keys(comics), function() {
var currentObject = comics[this];
var currentObject2 = comics[this].type;
console.log(currentObject2);
if (search == "") {
if(currentObject2 == "modern") {
var list = $("#comic__modern-list");
list.append(`
<div class="comic__box">
<div class="comic__image-box">
<img src="${currentObject['data-item-image']}" alt="${currentObject['data-item-description']}" class="img-fluid">
<div class="comic__desc-wrap">
<div class="comic__desc">${currentObject['data-item-description']}, issue #${currentObject['issue']} (${currentObject['year']})</div>
</div>
</div>
<div style="text-align:center; margin-top: 1rem">
<button
class="btn btn-warning snipcart-add-item comic__button"
data-item-id="${currentObject['data-item-id']}"
data-item-price="${currentObject['data-item-price']}"
data-item-url="${currentObject['data-item-url']}"
data-item-description="${currentObject['data-item-description']}"
data-item-image="${currentObject['data-item-image']}"
data-item-name="${currentObject['data-item-name']}">
<div class="comic__desc-desk">£${currentObject['data-item-price']}<br>Add to cart</div><div class="comic__desc-mob">BUY <br> ${currentObject['data-item-description']}, Issue: ${currentObject['issue']} (${currentObject['year']})</div>
</button>
</div>
</div>
`)
}
}
});
From what I can gather, this has to do with the keyword "this" no longer meaning what it did when it was outside of the function, so I'm assuming the fix will be to do with bind(), but I can't make heads nor tails of it.
p.s, if there's an easier/simpler way to set up a search system, please enlighten me!
User can, by pressing a button, select a particular topic of interest. When that happens, various divs will either become visible or invisible depending on whether that div has a link referring to that topic.
function GetPostsByTopic(topic) {
var area = document.getElementById("postArea");
var topicAreas = area.getElementsByClassName("topicArea");
for (i = 0; i < topicAreas.length; i++) {
var children = topicAreas[i].children;
var topics = [];
for (j = 0; j < children.length; j++) {
topics.push(children[j].getAttribute("asp-route-name"));
document.getElementById("firstTest").innerHTML = children[j].toString();
}
var b = topics.includes(topic);
if (b == true) {
var parentId = document.getElementById(topicAreas[i]).parentNode.id;
document.getElementById(parent).style.display = 'block';
} else {
document.getElementById(parent).style.display = 'none';
}
}
}
<div class="topicBox">
<button class="topicButton" onclick="GetPostsByTopic('Pets')">Pets</button>
<button class="topicButton" onclick="GetPostsByTopic('Vacation')">Vacation</button>
</div>
<div id="postArea">
<div class="post" id="post1">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
<div class="post" id="post2">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Vacation">Vacation</a>
</div>
</div>
<div class="post" id="post3">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
</div>
The trouble, as far as I can tell, begin early in the JS part. I can see that when a do var children=topicAreas[i].children, I get nothing.
I hope this is what you're trying to do. Based on what button you click, respective div is displayed.
function GetPostsByTopic(topic) {
var area = document.getElementById("postArea");
var topicAreas = area.getElementsByClassName("topicArea");
for (i = 0; i < topicAreas.length; i++) {
var children = topicAreas[i].children;
for (j = 0; j < children.length; j++) {
var parentId = topicAreas[i].parentNode.id;
if(children[j].getAttribute("asp-route-name") === topic){
document.getElementById(parentId).style.display = 'block';
}else{
document.getElementById(parentId).style.display = 'none';
}
}
}
}
<div class="topicBox">
<button class="topicButton" onclick="GetPostsByTopic('Pets')">Pets</button>
<button class="topicButton" onclick="GetPostsByTopic('Vacation')">Vacation</button>
</div>
<div id="postArea">
<div class="post" id="post1">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
<div class="post" id="post2">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Vacation">Vacation</a>
</div>
</div>
<div class="post" id="post3">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
</div>
Children isn't the issue. When you run your code you get the error "Uncaught TypeError: Cannot set property 'innerHTML' of null". Looking at your code where you are using .innerHTML, we see that you are trying to reference an element that you don't have in this code:
document.getElementById("firstTest")
Now, after adding that, you still have some items that you should change.
asp-action and asp-route-name are invalid HTML. Are you using a
framework that requires this syntax?
Don't use .getElementsByClassName().
Use .querySelectorAll() and Array.forEach() on the result for
easier looping.
Don't use .innerHTML when you aren't working with HTML strings as there are security and performance implications to doing so.
Avoid inline styles when you can. Using them causes duplication of code and code is harder to scale. Instead, use CSS classes and the .classList API.
It's not super clear exactly what is supposed to happen when clicking your buttons, but see the updated code below:
function GetPostsByTopic(topic) {
var area = document.getElementById("postArea");
// Don't use .getElementsByClassName() as it provides a live node list
// and causes quite a performance hit, especially when used in loops.
// Use .querySelectorAll() and then use .forEach() on the collection that
// it returns to iterate over them.
area.querySelectorAll(".topicArea").forEach(function(area){
var topics = [];
// No need for children, here. Again, use .querySelectorAll()
area.querySelectorAll("*").forEach(function(child) {
topics.push(child.getAttribute("asp-route-name"));
document.getElementById("firstTest").textContent = child.getAttribute("asp-route-name");
});
if (topics.indexOf(topic) > -1) {
// Don't use inline styles if you can avoid it.
// Instead use pre-made classes.
area.classList.add("hidden");
}
else {
area.classList.remove("hidden");
}
});
}
/* Use CSS classes when possible instead of inline styles */
.hidden { display:none; }
<div class="topicBox">
<button class="topicButton" onclick="GetPostsByTopic('Pets')">Pets</button>
<button class="topicButton" onclick="GetPostsByTopic('Vacation')">Vacation</button>
</div>
<div id="postArea">
<div class="post" id="post1">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
<div class="post" id="post2">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Vacation">Vacation</a>
</div>
</div>
<div class="post" id="post3">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
</div>
<div id="firstTest"></div>
I am trying to get first letter of firstname and lastname from a div and paste it in another div but it is pasting the same value in all divs and not taking unique value from each div.
Working Fiddle: https://jsfiddle.net/bv7w8dxg/1/
Issue Fiddle: https://jsfiddle.net/bv7w8dxg/
var takword = $('.nameholder').text().split(' ');
var text = '';
$.each(takword, function () {
text += this.substring(0, 1);
});
$('.avatarholder').text(text);
Markup
`
John Doe
<div class="main-holder">
<div class="nameholder">Kyle Davis</div>
<div class="avatarholder"></div>
</div>
<div class="main-holder">
<div class="nameholder">Seim Seiy</div>
<div class="avatarholder"></div>
</div>
<div class="main-holder">
<div class="nameholder">Momma Boy</div>
<div class="avatarholder"></div>
</div>`
You are using class selectors, which selects all elements with the given class name. That's why you have all the elements set with same value
You need to wrap your elements then process each row independently
I updated your code snippet to demonstrate this:
$('.row').each(function() {
var takword = $('.nameholder', this).text().split(' ');
var text = '';
$.each(takword, function () {
text += this.substring(0, 1);
});
$('.avatarholder', this).text(text);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="row">
<div class="nameholder">John Doe</div>
<div class="avatarholder"></div>
</div>
<div class="row">
<div class="nameholder">Kyle Davis</div>
<div class="avatarholder"></div>
</div>
<div class="row">
<div class="nameholder">Seim Seiy</div>
<div class="avatarholder"></div>
</div>
<div class="row">
<div class="nameholder">Momma Boy</div>
<div class="avatarholder"></div>
</div>
I have a little problem with my HTML template for convert to JSON. I wish convert a list of HTML messages to JSON. Thank you in advance for your response.
HTML Template
<div class="message">
<div class="message-data">
<div class="infos">
<h4 class="pseudo">Name</h4>
<span class="date">MM/DD/YYYY</span>
<span class="time">HH:MM</span>
</div>
</div>
<div class="message-content">
<div class="message-text">
Message here
</div>
</div>
</div>
<!-- Others .message -->
JSON Render
{
"list": [
{
"pseudo": "Name",
"date": "MM/DD/YYYY",
"time": "HH:MM",
"message": "Message here"
},
/* ... */
]
}
even if it doesn't look that cool I think this will be much faster:
var pseudo = document.getElementsByClassName("pseudo");
var date = document.getElementsByClassName("date");
var time = document.getElementsByClassName("time");
var message = document.getElementsByClassName("message-text");
var list = [];
for(var i=0, l=pseudo.length;i<l;i++) {
list.push({
pseudo: pseudo[i].textContent,
data: date[i].textContent,
time: time[i].textContent,
message: message[i].textContent
})
}
console.log(list);
.. depending on your file structure this may not be the best solution
You can use jQuery to simply extract your date from html:
var result = [];
$(".message").each(function() {
var obj = {
pseudo: $(this).find(".pseudo").text(),
date: $(this).find(".date").text(),
time: $(this).find(".time").text(),
message: $(this).find(".message-text").text(),
};
result.push(obj);
})
console.log(result)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="message">
<div class="message-data">
<div class="infos">
<h4 class="pseudo">Name</h4>
<span class="date">MM/DD/YYYY</span>
<span class="time">HH:MM</span>
</div>
</div>
<div class="message-content">
<div class="message-text">
Message here
</div>
</div>
</div>
<div class="message">
<div class="message-data">
<div class="infos">
<h4 class="pseudo">John</h4>
<span class="date">09/11/2011</span>
<span class="time">HH:MM</span>
</div>
</div>
<div class="message-content">
<div class="message-text">
World Disaster
</div>
</div>
</div>
Simply get all your .message elements, and cycle through them to add their properties to the resulting Array (I used trim() to remove extra spaces at the beginning and the end of the message texts):
console.log( messagesToJSON() );
function messagesToJSON(){
var messages = [],
elements = $('.message');
for(var i=0; i<elements.length; i++){
messages.push({
"pseudo": elements.eq(i).find('.pseudo').text(),
"date": elements.eq(i).find('.date').text(),
"time": elements.eq(i).find('.time').text(),
"message": elements.eq(i).find('.message-text').text().trim()
});
}
return {list: messages};
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="message">
<div class="message-data">
<div class="infos">
<h4 class="pseudo">Kevin</h4>
<span class="date">08/01/2016</span>
<span class="time">14:52</span>
</div>
</div>
<div class="message-content">
<div class="message-text">
Hi there!
</div>
</div>
</div>
<div class="message">
<div class="message-data">
<div class="infos">
<h4 class="pseudo">Robert</h4>
<span class="date">08/01/2016</span>
<span class="time">15:03</span>
</div>
</div>
<div class="message-content">
<div class="message-text">
Hello
</div>
</div>
</div>