Javascript: Select all data-qa attributes on HTML Page - javascript

Using only JavaScript, without the use of JQuery etc, what is the most efficient way to select all attributes names that have a certain data attribute (let's say data-qa).
<p data-foo="0"></p><br/><h6 data-qa="apple"></h6>
<p data-foo="0"></p><br/><h6 data-qa="book"></h6>
<p data-foo="0"></p><br/><h6 data-qa="car"></h6>
Expected result should be list :
apple
book
car
This question gets the parent elements, I want the attributes themselves. Select all elements with "data-" attribute without using jQuery
Resources:
Selenium find element via Data-Qa attribute
Data-QA Attribute: A better way to select elements for UI test automation

The code below works by getting all of the elements using document.querySelectorAll, mapping the elements to the values of the data attributes, and then filtering out the ones that are falsy or '0'.
let getAllDataAttrs = name => Array.from(
document.querySelectorAll(`[data-${name}]`)
).map(elem => elem.getAttribute(`data-${name}`))
.filter(val => val && val !== '0');
console.log(getAllDataAttrs('foo'));
<p data-foo="0"></p><br/>
<h6 data-foo="apple"></h6>
<p data-foo="0"></p><br/>
<h6 data-foo="book"></h6>
<p data-foo="0"></p><br/>
<h6 data-foo="car"></h6>

For reference, below is essentially the core vanilla javascript functionality needed ...
Using querySelectorAll, querySelector and getElementById should get you started.
// get "data-qa" value by "id"
var data = document.getElementById('id-test2').getAttribute('data-qa');
console.log(data);
// get "id" value by "data-qa"
var data = document.querySelector('[data-qa="data-qa-test2"]').id;
console.log(data);
// get all elements with attribute "data-qa"
var elems = document.querySelectorAll('[data-qa]');
// get all "ids"
var data = [];
elems.forEach(function(elem){
data.push(elem.id);
});
console.log(data);
// get all "data-qa"
var data = [];
elems.forEach(function(elem){
data.push(elem.getAttribute('data-qa'));
});
console.log(data);
<div id="id-test" data-qa="data-qa-test"></div>
<div id="id-test1" data-qa="data-qa-test1"></div>
<div id="id-test2" data-qa="data-qa-test2"></div>
<div id="id-test3" data-qa="data-qa-test3"></div>

Related

getElementsByClassName not working when I change to different class name

I've looked over numerous Stack Overflow discussions on getElementsByClassName but can't seem to find anything that can help me resolve this particular issue. To explain . . .
I have the following javascript
field_to_update.innerHTML = '';
var elOptNew = document.createElement('option');
elOptNew.text = '---'
elOptNew.value = '';
field_to_update.add(elOptNew);
field_to_update.options[0].selected = true;
var track_names = document.getElementsByClassName('wpaudio');
for (i=0; i<track_names.length; i++) {
var track_name = track_names[i].innerHTML;
var elOptNew = document.createElement('option');
elOptNew.text = track_name.replace("&", "&");
elOptNew.value = track_name;
field_to_update.add(elOptNew); // standards compliant; doesn't work in IE
}
and I am looking to extract the names of a list of audio files using the line var track_names = document.getElementsByClassName('wpaudio') which refers to the following code included in the functions.php file of a wordpress child theme.
<ol id="audioFilesList" class="reactionFormAudio">
<?php
// loop through rows (parent repeater)
while( have_rows('song_upload') ): the_row(); ?>
<li><p class="wpaudio" name="audioFileName"><?php the_sub_field('track_name'); ?></p><br>
The above scenario works fine. BUT i have decided to not use the ordered list of audio files as listed above - but instead us the default audio playlist that can be created within a wordpress post, which produces the following code:
<div class="wp-playlist-tracks">
<div class="wp-playlist-item wp-playlist-playing">
<a class="wp-playlist-caption" href="https://www.futureproofpromotions.com/wp-content/uploads/2020/09/01_WhereToBegin-128.mp3">
1.
<span class="wp-playlist-item-title">
“Where To Begin” </span>
<span class="wp-playlist-item-artist"> — Alice Clayton</span>
</a>
<div class="wp-playlist-item-length">2:57</div>
</div>
<div class="wp-playlist-item">
<a class="wp-playlist-caption" href="https://www.futureproofpromotions.com/wp-content/uploads/2020/09/02_BeingAlone-128.mp3">
2.
<span class="wp-playlist-item-title">
“Being Alone” </span>
<span class="wp-playlist-item-artist"> — Brosnan</span>
</a>
<div class="wp-playlist-item-length">3:15</div>
</div>
</div>
</div>
However, when I swap the javascript line from document.getElementsByClassName('wpaudio'); to document.getElementsByClassName('wp-playlist-caption'); in order to reference the different class name in the the new html, it doesn't display any names!
I am very new indeed to javascript so this may be obvious to someone skilled in that language, but I do have a limited knowlege of php.
Would anybody be able to explain why when i change the class name/reference in the above scenario I get no names displayed?
FYI I have also tried changing document.getElementsByClassName() to document.querySelectorAll() which also works well, when referencing the original class ('.wpaudio') - but again produces no result when referencing ('.wp-playlist-caption') or any other class name nested within it (such as .wp-playlist-item-title or .wp-playlist-item-artist).
Any help with the above would be most appreciated
Since wp-playlist-caption has multiple nested elements, you can either query for each one of them and string them together or take the lazy route and use .innerText. That will extract the rendered plaintext inside the element and its children.
// Wait until the page has loaded
document.addEventListener('DOMContentLoaded', () => {
var field_to_update = document.getElementById('reactionForm_strongestTrack');
field_to_update.innerHTML = '';
var elOptNew = document.createElement('option');
elOptNew.text = '---'
elOptNew.value = '';
field_to_update.add(elOptNew);
field_to_update.options[0].selected = true;
// Search for all playlist-captions inside the playlist-tracks list.
// 'Currently playing' has a playlist-caption too,
// limiting to the tracklist excludes it
document.querySelectorAll('.wp-playlist-tracks .wp-playlist-caption')
.forEach( // The following arrow function will be called for each element
track => {
// There are nested elements but we just want the plaintext
let track_name = track.innerText;
// Create a new element and append to the select as before
let elOptNew = document.createElement('option');
elOptNew.text = track_name.replace("&", "&");
elOptNew.value = track_name;
field_to_update.add(elOptNew);
});
});
Additional reference for arrow functions.

Get the href value using HTML5 data attributes

I would like to get the value of the href i.e. the web link using the data attribute.
I have the following snippet of code
<div class="my-item-details">
<h3 class="my-item-title" data-item_item="x12">
<a href="http://link.com">
My Classic Box
</a>
</h3>
<span class="my-item-price" data-item_item="x12">
38.00
</span>
</div>
The following 2 snippets give the right output.
var price_val = $('.my-item-price[data-item_uuid=x12]').text();
price_val = $.trim(price_val)
console.log(price_val);
38.00
var item_name = $('.my-item-title[data-item_uuid=x12]').text();
item_name = $.trim(item_name)
console.log(item_name);
My Classic Box
However when I run this code
var item_link = $('.my-item-title[data-item_uuid=x12]').attr("href");
item_link = $.trim(item_link)
console.log(item_link);
I get an empty string instead of http://link.com
What am I missing?
.my-item-title[data-item_uuid=x12] selects the h3 element, which doesn't have an href attribute.
Only the a element has that.
Add a descendant combinator and a type selector:
.my-item-title[data-item_uuid=x12] a
You are trying to get the attribute href from a <h3> element without href property:
You could make a change on your selector this way to get the correct result:
var item_link = $('.my-item-title[data-item_uuid=x12] > a').attr("href");
This should give you the correct value.

How do I change more than one element?

EDIT: I changed the var to class but I might have some error in here.
Here it goes, I want to have this paragraph in which the user can change the name on the following paragraph. The code I'm using only changes one name but the rest remains the same.
<script type="text/javascript">
function changey(){
var userInput = document.getElementById('userInput').value;
var list = document.getElementByClassName('kiddo');
for (let item of list) {
item.innerHTML = userInput;
}
}
</script>
<input id="userInput" type="text" value="Name of kid" />
<input onclick="changey()" type="button" value="Change Name" /><br>
Welcome to the site <b class="kiddo">dude</b> This is how you create a document that changes the name of the <b class="kiddo">dude</b>. If you want to say <b class="kiddo">dude</b> more times, you can!
No error messages, the code only changes one name instead of all three.
Use class="kiddo" instead of id in the html.
You can then use var kiddos = document.getElementsByClassName('kiddo') which will return an array of all the elements of that class name stored in kiddos.
Then you just need to loop through the values and change what you want.
Example of loop below:
for (var i = 0; i < kiddos.length; i++) {
kiddos[i].innerHTML = userInput;
}
id should be unique on the page. Javascript assumes that there is only one element with any given id. Instead, you should use a class. Then you can use getElementsByClassName() which returns an entire array of elements that you can iterate over and change. See Select ALL getElementsByClassName on a page without specifying [0] etc for an example.
Hello You should not use id, instead use class.
Welcome to the site <b class="kiddo">dude</b> This is how you create a document that changes the name of the <b class="kiddo">dude</b>. If you want to say <b class="kiddo">dude</b> more times, you can!
After That on Js part :
<script type="text/javascript">
function changey(){
var userInput = document.getElementById('userInput').value;
var list = document.getElementByClassName('kiddo');
for (let item of list) {
item.innerHTML = userInput;
}
}
</script>
you should use class instated of id. if you use id then the id [kiddo] must be unique
In short, document.querySelectorAll('.kiddo') OR
document.getElementsByClassName('kiddo') will get you a list of elements to loop through. Take note of querySelectorAll, though - it uses a CSS selector (note the dot) and doesn't technically return an array (you can still loop through it, though).
See the code below for some full working examples (const and arrow functions are similar to var and function, so I'll put up a version using old JavaScript, too):
const formEl = document.querySelector('.js-name-change-form')
const getNameEls = () => document.querySelectorAll('.js-name')
const useNameFromForm = (formEl) => {
const formData = new FormData(formEl)
const nameValue = formData.get('name')
const nameEls = getNameEls()
// Set the text of each name element
// NOTE: use .textContent instead of .innerHTML - it doesn't get parsed, so it's faster and less work
nameEls.forEach(el => el.textContent = nameValue)
}
// Handle form submit
formEl.addEventListener('submit', (e) => {
useNameFromForm(e.target)
e.preventDefault() // Prevent the default HTTP request
})
// Run at the start, too
useNameFromForm(formEl)
.name {
font-weight: bold;
}
<!-- Using a <form> + <button> (submit) here instead -->
<form class="js-name-change-form">
<input name="name" value="dude" placeholder="Name of kid" />
<button>Change Name</button>
<form>
<!-- NOTE: Updated to use js- for js hooks -->
<!-- NOTE: Changed kiddo/js-name to spans + name class to remove design details from the HTML -->
<p>
Welcome to the site, <span class="js-name name"></span>! This is how you create a document that changes the name of the <span class="js-name name"></span>. If you want to say <span class="js-name name"></span> more times, you can!
</p>
var formEl = document.querySelector('.js-name-change-form');
var getNameEls = function getNameEls() {
return document.querySelectorAll('.js-name');
};
var useNameFromForm = function useNameFromForm(formEl) {
var formData = new FormData(formEl);
var nameValue = formData.get('name');
var nameEls = getNameEls(); // Set the text of each name element
// NOTE: use .textContent instead of .innerHTML - it doesn't get parsed, so it's faster and less work
nameEls.forEach(function (el) {
return el.textContent = nameValue;
});
};
// Handle form submit
formEl.addEventListener('submit', function (e) {
useNameFromForm(e.target);
e.preventDefault(); // Prevent the default HTTP request
});
// Run at the start, too
useNameFromForm(formEl);
<button class="js-get-quote-btn">Get Quote</button>
<div class="js-selected-quote"><!-- Initially Empty --></div>
<!-- Template to clone -->
<template class="js-quote-template">
<div class="js-quote-root quote">
<h2 class="js-quote"></h2>
<h3 class="js-author"></h3>
</div>
</template>
You have done almost everything right except you caught only first tag with class="kiddo".Looking at your question, as you need to update all the values inside tags which have class="kiddo" you need to catch all those tags which have class="kiddo" using document.getElementsByClassName("kiddo") and looping over the list while setting the innerHTML of each loop element to the userInput.
See this link for examples:https://www.w3schools.com/jsref/met_document_getelementsbyclassname.asp
try:
document.querySelectorAll('.kiddo')
with
<b class="kiddo">dude</b>

Using javascript to get sum from input title

Below is a javascript which is able to get the input value & needs external libraries.
I know this seem odd but I have to use javascript to grab the price from the input title and no external libraries is required. Is it possible to work from input title ?
<?php
include_once('database_conn.php');
$sqlCDs = 'SELECT CDID, CDTitle, CDYear, catDesc, CDPrice FROM nmc_cd b inner join nmc_category c on b.catID = c.catID WHERE 1 order by CDTitle';
$rsCDs = mysqli_query($conn, $sqlCDs);
while ($CD = mysqli_fetch_assoc($rsCDs)) {
//have a look at the input field below
echo "\t<div class='item'>
<span class='CDTitle'>{$CD['CDTitle']}</span>
<span class='CDYear'>{$CD['CDYear']}</span>
<span class='catDesc'>{$CD['catDesc']}</span>
<span class='CDPrice'>{$CD['CDPrice']}</span>
<span class='chosen'><input type='checkbox' id="yourId" name='CD[]' value='{$CD['CDID']}' title='{$CD['CDPrice']}' /></span>
</div>\n";
}
?>
JS:
function isChecked(chosen) {
//and here it is called again
var valOfTitle = document.selectElementById("yourId").getAttribute('title');
var number = parseFloat(valOfTitle);
if(chosen.is(':checked')) {
sum = sum + parseFloat(valOfTitle);
} else {
sum = sum - parseFloat(valOfTitle);
}
$('#total').valOfTitle(sum.toFixed(2));
};
Just use getAttribute if you dont want to use any external libraries.
element.getAttribute("title")
i hope i understood you correctly:
you can access the data in your input field via jQuery's attr() method.
// "valOfTitle" is just a name..could also be "george" or "germany"
// "yourInputElementId needs to be the id of your element (written in
// "")
var valOfTitle = $(yourInputElementId).attr('title');
without jQuery:
var valOfTitle = document.selectElementById(yourInputFieldId).getAttribute('title');
if you want it as a number you can just do:
var number = parseFloat(valOfTitle);
if you don't want to add an id to your element you also can use another javascript selector, p.e. getElementsByName- but note: this will return a HTML Collection and not a single element, which means you will have to loop over this collection to access your data.
http://www.w3schools.com/jsref/met_doc_getelementsbyname.asp
maybe this google search may help you too:
https://www.google.de/search?q=javascript+selectors&oq=javascript+selectors&aqs=chrome..69i57.4015j0j7&sourceid=chrome&es_sm=91&ie=UTF-8#q=pure+javascript+selectors
or even
How can I use the jQuery-like selector in pure JavaScript

Get all ellements and attributes of an element root using jQuery

I need to find all elements name in tag and all attributes in each element by using JQuery , each element has different attributes name and value i need to know this attributes name and value but don't know how
<Circuit>
<C Type="Bipolar" Name="c1">
<Cathode row="10" col="20"/>
<Anode row="15" col="50"/>
</C>
<AND Name="and1">``
<Input>
<Pin row="10" col="40"></Pin>
<Pin row="20" col="40"></Pin>
</Input>
<Output>
<Pin row="30" col="50"></Pin>
</Output>
</AND>
<Diode Name="d1" Value="30">
<Anode row="30" col="50"></Anode>
<Cathode row="40" col="60"></Cathode>
</Diode>
<R Type="Constant" Name="r1">
<Node row="60" col="80"></Node>
<Node row="70" col="80"></Node>
</R>
</Circuit>
I'll explain what i need, first need to know all elements (tag name) only in tag
o/p like this
elements in circuit tag
C
AND
Diode
R
after this need to know all attributes and elements in each element
like this
first element (C) has 2 attribute
first attribute is "Type" and the value of this attribute ="Bipolar"
second attribute is "Name" and the value of this attribute ="c1"
and has 2 elements
Cathode
Anode
and the same in each element
In jQuery there is the attribute matcher [attr], out of many other selectors
$("[Name]")
will get you all the elements that has the attribute Name
you can then loop through and get the actual name with jQuerys attr() function
$("[Name]").each(function() {
console.log($(this).attr("Name"));
console.log($(this).attr("Value"));
});
Edit
In the comments I found out that the question actually is how to serialize the whole structure into a data set. Therefore this might be a possible duplicate https://stackoverflow.com/a/5287305/576725
The following prior question shows how to get all the attributes of an element using JavaScript. The same, and the elements can be obtained using jQuery:
Get all Attributes from a HTML element with Javascript/jQuery
So that your code works cross-browser define your xml variable as follows:
var xml = $( $.parseXML( 'XML-String' ) );
You can the get all the elements and attributes as follows:
var all = xml.find('*').map(function(v,i) {
var ux = {};
$.each( this.attributes, function(index, node) {
ux[ node.nodeName ] = node.nodeValue;
});
return $.extend({}, { nodeName: this.nodeName }, {attributes:ux});
})
.get();
Which should give you output that looks like:
[{"nodeName":"Circuit","attributes":{}},{"nodeName":"C","attributes":{"Type":"Bipolar","Name":"c1"}},{"nodeName":"Cathode","attributes":{"row":"10","col":"20"}}, ....... .. .. .. ]
JS FIDDLE DEMO

Categories

Resources