How can Javascript capture these values? - javascript

Let's say I have a webpage that has this in it:
<a href="https://www.youtube.com/analytics?vmv=2#fi=v-FLp5ViIYS7s" class="yt-uix-tooltip" title="View stats">
<span class="vm-video-metric video-view-count">
<span>
<span class="vm-video-metric-icon">
<img src="//s.ytimg.com/yt/img/pixel-vfl3z5WfW.gif" alt="">
</span>
<span class="vm-video-metric-value">
1,644
</span>
</span>
</span>
<span class="vm-video-metric video-likes-count">
<span>
<span class="vm-video-metric-icon">
<img src="//s.ytimg.com/yt/img/pixel-vfl3z5WfW.gif" alt="">
</span>
<span class="vm-video-metric-value">
13
</span>
</span>
</span>
<span class="vm-video-metric video-dislikes-count">
<span>
<span class="vm-video-metric-icon">
<img src="//s.ytimg.com/yt/img/pixel-vfl3z5WfW.gif" alt="">
</span>
<span class="vm-video-metric-value">
3
</span>
</span>
</span>
I would like to capture the three values encapsulated by the <span class="vm-video-metric-value"></span> tags.
In Javascript, this would normally be done using the id tag. But since there is no id tag, how can these values be captured?

Use the getElementsByClassName method, like so.
var elements = document.getElementsByClassName("vm-video-metric-value");
for (var i = 0; i < elements.length; i++) {
console.log(elements[i].innerHTML);
}

var qsa = document.querySelectorAll("span.vm-video-metric-value"), l = qsa.length, i;
var vals = [];
for( i=0; i<l; i++)
vals.push(parseInt(qsa[i].firstChild.nodeValue.replace(/[^0-9]/g,''),10));
vals is now an array containing the numbers you wanted extracted. Requires a browser capable of querySelectorAll, which almost all are (IE7 and down are not).

If you're using jQuery, and you should! It's really simple to learn and it will take you a week tops to start using it:
$('span.vm-video-metric-value').each(function() {
console.log($(this).text());
});
"For each span with class vm-video-metric-value, print the text inside to the console."
Easy as pie!
Please give jQuery a shot, it's a great library.

Related

How to make this code work with .each function?

I have the following piece of code in a script tag that I need to get working for all #tel ID elements on the page. I can only get it to work for the first #tel element. I've been trying to use .each function - but no luck...
The reason being is that I can't seem to get the ACF repeater URL to suit my needs here. The Advanced section of the dynamic content link part is not displaying. So I am trying to make a hack in an HTML widget for this.
But I need it to work for all buttons with button ID #tel.
Here's the code:
var link = document.getElementById('tel');
var href = link.getAttribute('href');
link.setAttribute('href', href.replace('http://', 'tel:'));
<div class="elementor-button-wrapper">
<a href="http://44400907" class="elementor-button-link elementor-button elementor-size-xs" role="button" id="tel">
<span class="elementor-button-content-wrapper">
<span class="elementor-button-text elementor-inline-editing" data-elementor-setting-key="text" data-elementor-inline-editing-toolbar="none">
44 40 09 07
</span>
</span>
</a>
</div>
In HTML/javascript element IDs must be unique. So in your case you can use class for that:
var links = document.querySelectorAll('.tel');
for(let i = 0; i < links.length; i++)
{
let link = links[i];
var href = link.getAttribute('href');
link.setAttribute('href', href.replace('http://', 'tel:'));
}
<div class="elementor-button-wrapper">
<a href="http://44400907" class="elementor-button-link elementor-button elementor-size-xs tel" role="button">
<span class="elementor-button-content-wrapper">
<span class="elementor-button-text elementor-inline-editing" data-elementor-setting-key="text" data-elementor-inline-editing-toolbar="none">44 40 09 07</span>
</span>
</a>
</div>
<div class="elementor-button-wrapper">
<a href="http://44400908" class="elementor-button-link elementor-button elementor-size-xs tel" role="button">
<span class="elementor-button-content-wrapper">
<span class="elementor-button-text elementor-inline-editing" data-elementor-setting-key="text" data-elementor-inline-editing-toolbar="none">44 40 09 08</span>
</span>
</a>
</div>
<div class="elementor-button-wrapper">
<a href="http://44400909" class="elementor-button-link elementor-button elementor-size-xs tel" role="button">
<span class="elementor-button-content-wrapper">
<span class="elementor-button-text elementor-inline-editing" data-elementor-setting-key="text" data-elementor-inline-editing-toolbar="none">44 40 09 09</span>
</span>
</a>
</div>

How do I hide a div if there's a certain string of text on another element?

I'm trying to only show class="important" whenever certain text/products like 'KR-KJSC-MICROBIT' and 'KR-KJSC-D' are on the page. When those texts are not on the page then this element should be hidden. Can anyone please assist me with this?
<div class="important">SHOW IF CERTAIN PRODUCTS ARE IN THE CART/THANK YOU PAGE</div>
<div class="cart-line-product-info>
<span class="cart-product-code">
<a class="product-code">Code: KR0KJSC-MICROBIT</a>
</span>
</div>
<div class="cart-line-product-info>
<span class="cart-product-code">
<a class="product-code">Code: KR-KJSC-D</a>
</span>
</div>
You can set a variable with the specific words you want to match.
Get html elements.
Iterates throught the product codes (anchors).
If words array includes the textContent of an anchor element, then display the importants elements:
let words = ['KR0KJSC-MICROBIT', 'KR-KJSC-D']
let anchors = document.querySelectorAll(".product-code")
let importants = document.querySelectorAll(".important");
for(let i = 0; i < anchors.length; i++){
if(words.includes(anchors[i].textContent.replace('Code: ', ''))){
importants.forEach(x => x.style.display = 'block')
} else {
importants.forEach(x => x.style.display = 'none')
}
}
<div class="important">SHOW IF CERTAIN PRODUCTS ARE IN THE CART/THANK YOU PAGE</div>
<div class="cart-line-product-info">
<span class="cart-product-code">
<a class="product-code">Code: KR0KJSC-MICROBIT</a>
</span>
</div>
<div class="cart-line-product-info">
<span class="cart-product-code">
<a class="product-code">Code: KR-KJSC-D</a>
</span>
</div>
Here is a way to do it. Not really the best solution but will work if you add the js script at end of page.
const codeElements = document.querySelectorAll(".product-code");
let codes = []
codeElements.forEach( element => codes.push(element.innerHTML))
if(!codes.includes("Code: KR-KJSC-D")) {
document.querySelector(".important").style.display = "none"
}
<div class="important">SHOW IF CERTAIN PRODUCTS ARE IN THE CART/THANK YOU PAGE</div>
<div class="cart-line-product-info>
<span class="cart-product-code">
<a class="product-code">Code: KR0KJSC-MICROBIT</a>
</span>
</div>
<div class="cart-line-product-info>
<span class="cart-product-code">
<a class="product-code">Code: KR-KJSC-D</a>
</span>
</div>
let pageSource = document.documentElement.innerHTML
// regex match for target strings against page source
if(pageSource.match(/KR0KJSC-MICROBIT|KR-KJSC-D/g)){
$('.important').show()
}

How to get an Attribute from Each Result of querySelectorAll()

I am trying to do this:
Search for all the spans in my structure
Get the id value from each span
Update the parent with that text for test purposes
The reason for this work is that I am doing front-end customizations for an application and trying get some WAI-ARIA labelled-by values set on a parent element.
The problem is that many of the needed values come from an COTS application that I am working with/around. These needed input are not always set in a good sequence in the DOM.
I have been looking at a JS solution to get around this.
<div class="fluid-form-container">
<ul id="accordionGroup" class="Accordion" data-allow-multiple="">
<li class="fluid-form-group-container">
<h3 aria-labelledby="accordion1id">
<button aria-expanded="true" class="Accordion-trigger" aria-controls="sect1" id="accordion1id">
<span class="Accordion-title"><div class="fluid-form-title">
<div class="FormSection">
<span id="More_Info_Form_Section_Label">More Info</span>
</div>
</div>
</span>
</button>
</h3>
</li>
<li class="fluid-form-group-container">
<h3 aria-labelledby="accordion2id">
<button aria-expanded="true" class="Accordion-trigger" aria-controls="sect2" id="accordion2id">
<span class="Accordion-title"><div class="fluid-form-title">
<div class="FormSection">
<span id="Even_More_Info_Form_Section_Label">Even More Info</span>
</div>
</div>
</span>
</button>
</h3>
</li>
</div>
//My bad javaScript so far
var found_elements = [];
var outers = document.querySelectorAll('.FormSection');
for(var i=0; i<outers.length; i++) {
var elements_in_outer = outers[i].querySelectorAll("span");
var updateValue = elements_in_outer.getAttr("id");
outers[i].closest("h3").innerHTML = updateValue;
}
The expect results:
- parent tag innerHTML set to the id value of each span in the structure
Actual results:
- I'm getting errors because I am not sure what I need to use to get that id from each span found
querySelectorAll() returns a NodeList , so elements_in_outer.getAttr("id") won't work and should be replaced with querySelector()
there is no getAttr, use getAttribute
( i replaced your for with a forEach )
var found_elements = [];
var outers = document.querySelectorAll('.FormSection').forEach(div => {
var elements_in_outer = div.querySelector("span");
var updateValue = elements_in_outer.getAttribute("id");
div.closest("h3").innerHTML = updateValue;
});
<div class="fluid-form-container">
<ul id="accordionGroup" class="Accordion" data-allow-multiple="">
<li class="fluid-form-group-container">
<h3 aria-labelledby="accordion1id">
<button aria-expanded="true" class="Accordion-trigger" aria-controls="sect1" id="accordion1id">
<span class="Accordion-title"><div class="fluid-form-title">
<div class="FormSection">
<span id="More_Info_Form_Section_Label">More Info</span>
</div>
</div>
</span>
</button>
</h3>
</li>
<li class="fluid-form-group-container">
<h3 aria-labelledby="accordion2id">
<button aria-expanded="true" class="Accordion-trigger" aria-controls="sect2" id="accordion2id">
<span class="Accordion-title"><div class="fluid-form-title">
<div class="FormSection">
<span id="Even_More_Info_Form_Section_Label">Even More Info</span>
</div>
</div>
</span>
</button>
</h3>
</li>
</div>
If you know beforehand that you will only use the span elements that have an id, then use [id] in the querySelectorAll selector likewise
document.querySelectorAll('span[id]')
If you will use that as an array, then you need
[... document.querySelectorAll('span[id]')]
Assigning the new value would be something like this:
[... document.querySelectorAll('span[id]')].forEach(s => s.closest("h3").innerHTML = s.id)

Get element by classname inside certain div

I am trying to click some buttons in a page which has this html code
<div class="a">
<span>
<a class="b" role="button">test</a>
</span>
</div>
So what i've tried is to take ONLY the div's class a
var buttons = document.getElementsByClassName('a').getElementsByClassName('b');
for(var i = 0; i <= buttons.length; i++)
buttons[i].click();
Is there anyway to get the button with class name b but Only the one that is inside the div with class name a ??
P.S. i have also tried and this
var buttons = document.getElementsByClassName('a').getElementsByTagName('span').getElementsByClassName('b');
for(var i = 0; i <= buttons.length; i++)
buttons[i].click();
But i get an empty array [ ] as a response when I console.log(buttons)
You can use querySelector to overcome the issue.
document.querySelectorAll("div.a a.b");
You can use jquery and do
var buttons = $('.a > .b');
Here's an XPath solution:
let res = document.evaluate('//*[#class="a"]//*[#class="b"]',document,null,XPathResult.ANY_TYPE,null);
res.iterateNext().click();
<div class="a">
<span>
<a class="b" role="button" onclick="console.log('clicked!')">test</a>
</span>
</div>
Unfortunately Internet Explorer still doesn't support the XPath API.
Since only one div will be assigned the class='a', you can either supply an ID instead, or, you can do this :
var spans = document.getElementsByClassName('a')[0].getElementsByTagName('span');
// [0] indicates the first element with the class='a'
for(var i = 0; i < spans.length; i++) {
spans[i].getElementsByClassName('b')[0].click();
}
<div class="a">
<span>
<a class="b" role="button" href="javascript:void(0)" onclick="console.log(this.innerHTML+' was clicked !')">test 1</a>
</span>
<span>
<a class="b" role="button" href="javascript:void(0)" onclick="console.log(this.innerHTML+' was clicked !')">test 2</a>
</span>
<span>
<a class="b" role="button" href="javascript:void(0)" onclick="console.log(this.innerHTML+' was clicked !')">test 3</a>
</span>
</div>
This works perfectly, here it is : https://jsfiddle.net/nd8m7mms/4/

Add div as only child of a node

I am trying to add div as only child to a node. and if that node already has any children make them children of the div.
original DOM looks like:
<a href = "">
<span id="gsp" > </span>
<span id="gbsp"> some text </span>
</a>
I want the output to be:
<a href = "">
<div id="oaa_web_accessibility_highlight">
<span id="gsp" > </span>
<span id="gbsp"> some text </span>
</div>
</a>
instead, below snippet gives me:
<a href = "">
<div id="oaa_web_accessibility_highlight"> </div>
<span id="gsp" > </span>
<span id="gbsp"> some text </span>
</a>
I am trying to use the below snippet, but it is not working.
var new_div_element = this.document.createElement('div');
new_div_element.id = 'oaa_web_accessibility_highlight';
node.insertBefore(new_div_element, node.childNodes[0]);
for (var i =0; i < node.childNodes.length; i++) {
if (i == 0) continue;
node.childNodes[0].appendChild(node.childNodes[i]);
}
please can anyone help me on this?
Do it like this:
var new_div_element = document.createElement('div');
new_div_element.id = 'oaa_web_accessibility_highlight';
while (node.firstChild) {
new_div_element.appendChild(node.firstChild);
}
node.appendChild(new_div_element);
This empties the children of node into new_div_element, and then appends new_div_element to the now empty node.
It doesn't use innerHTML, so you're not destroying any state of the elements being transferred.
FYI, the reason yours didn't work properly was that your loop is incrementing i, but you're removing elements from the .childNodes list when you do the .appendChild.
Since .childNodes is a live list, its content is updated when you move one of its items to a different location. As a result, after the first child is removed, the second child takes its place at that index. Since your i is incremented, it skips passed the one(s) that were relocated in the list.
If you're willing to use jQuery, it has a wrapAll method that does this for you.
$(node).children().wrapAll('<div id="oaa_web_accessibility_highlight"></div>');

Categories