CSS selector to match elements by attribute's name start - javascript

Is there any CSS selector to match these elements? (I need it for adblocker config, looked at W3C selectors document - no hints found there. Generic solution needed because part after data-d- gets randomized by the site).
<div data-d-9y3x>
<div data-d-m01>
<div data-d-whatever>

No, there is currently no way to select elements based on the presence of an attribute whose name is starting with a certain value. The starts with selection is only possible for attribute values.
Such a selector is not mentioned in the CSS Selectors Level 4 spec also and so it doesn't look like it would be available anytime soon.
You have the following choices:
Use group of selectors with all possible attribute name values in the format element[attribute-name]. But this option is not viable when the exact attribute names are not fixed/unknown.
Use JavaScript (or some other scripting library of your preference). Below is a very quick rough sample for the benefit of future visitors.
var el = document.getElementsByTagName('div');
for (var i = 0; i < el.length; i++) {
var attr = el[i].attributes; /* get all attributes on the element */
for (var j = 0; j < attr.length; j++) {
if (attr[j].name.indexOf('data-') == 0) { /* if element has an attribute whose name has data- */
el[i].style.color = 'red';
break;
}
}
}
<div data-d-9y3x>Some</div>
<div data-d-m01>text</div>
<div data-d-whatever>content</div>
<div test-data-d-whatever>and</div>
<div d-whatever>more</div>
<div testdata-d-whatever>...</div>

With ES6+ you can use spread operator (...) and then filter those element that their attribute names' start with data-d-:
var res = [...document.querySelectorAll("*")]
.filter(t => [...t.attributes]
.filter(({ name }) => name.startsWith("data-d-")).length > 0)
console.log(res);
<div data-d-9y3x>Some</div>
<div data-d-m01>text</div>
<div data-d-whatever>content</div>
<div test-data-d-whatever>and</div>
<div d-whatever>more</div>
<div testdata-d-whatever>...</div>

Related

Select nested elements by name attribute javascript(no jquery)

So I have this HTML code and I need to select the elements by their name attribute. The problem is I have multiple elements with the same structure and I need to go throw them with a loop.
<div class="res">
<h4 name="title">title</h4>
<span name="span1"></span>
<span name="span2"></span>
<p name="p1"></p>
<p name="p2"></p>
</div>
I need to select each one of the elements inside the .res div element by their name(or if there's a better solution I'd like to you).
document.getElementsByName("res");
document.getElementsByName("title");
document.getElementsByName("span");
or you can loop through the elements if you don't want to hard-code the name.
You could use .querySelector() like :
document.querySelector('[name="xxxxxx"]');
If you want to loop through all the res containers you could use .querySelctorAll() like :
var containers = document.querySelectorAll('.res');
for( var i = 0; i < containers.length; i++) {
console.log( containers[i].querySelector('[name="title"]').textContent );
}
You can use the DOM Element.children attribute in pure javascript
var children = res.children;
for (var i = 0; i < children.length; i++) {
var child = children[i];
// Do stuff
}
You can use querySelectorAll and inside loop handle every element.
const elements = document.querySelectorAll(".res > *");
elements.forEach(element => {
console.log(element);
});
<div class="res">
<h4 name="title">title</h4>
<span name="span1"></span>
<span name="span2"></span>
<p name="p1"></p>
<p name="p2"></p>
</div>

Show/Hide Elements with multiple attributes by attribute selection (Javascript)

I try to find an easy solution (I am a totally coding beginner, just use javascript in widgets of a "out of the box" page) for the following problem:
There are multiple attributes visitor can select by click Remove/Show
attribute a (Remove/Show)
attribute b (Remove/Show)
attribute c (Remove/Show)
a.s.o.
based on visitors "selection", I would like to show or hide the list of elements:
element 1 (attribute a and b) - Remove if "a" OR "b" has been selected
element 2 (attribute a) - remove if "a" has been selected
element 3 (attribute a and c) - remove, if "a" OR "c" has been selected
a.s.o.
I am able already to hide elements based on a "selection", but in my solution every element show and hide only based on the unique ID (and so also only on the single selection).
The Javascript I found for that is:
<script type="text/javascript">
//<![CDATA[
function swap(openlink,closelink, linkid, dataid)
{
if( document.getElementById(dataid).style.display == 'none')
{
document.getElementById(dataid).style.display='inline';
document.getElementById(linkid).firstChild.nodeValue=closelink;
} else
{
document.getElementById(dataid).style.display='none';
document.getElementById(linkid).firstChild.nodeValue=openlink;
}
}
//]]>
</script>
And than I could use this HTML Code to Remove/Show the elements:
attribute a Remove
attribute b Remove
attribute c Remove
And my element will be Remove/Show by this:
<div id="showmeA" style="display:inline">Element 1</div>
<div id="showmeB" style="display:inline">Element 2</div>
<div id="showmeB" style="display:inline">Element 3</div>
Is there an easy way to add 2 ids to one "element", so that for example Element 1 could be hidden by id=showmeA AND id=showmeB?
You said the issue yourself: IDs are unique.
This is exactly why you should use something else than id, and class attribute is perfectly fine as it does not have to be unique.
Then, this means that the function will not look for your elements using getElementById() but getElementsByClassName().
Note that this function get elements, this involves that you have to loop through these elements and hide / show the ones targeted.
function swap(openlink, closelink, linkid, dataclass) {
var elements = document.getElementsByClassName(dataclass);
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
if(element.style.display == 'none') {
element.style.display='inline';
document.getElementById(linkid).firstChild.nodeValue=closelink;
} else {
element.style.display='none';
document.getElementById(linkid).firstChild.nodeValue=openlink;
}
}
}
Do not forget to replace id by class attributes to your HTML, you can put in as much as you want, they simply must be separated by a space:
<div class="showmeA showmeB">Element 1</div>
<div class="showmeB">Element 2</div>
<div class="showmeC">Element 3</div>
Here is an example that you can use to better understand the function and attributes used in your solution, this solves your issue: https://jsfiddle.net/sy2mxscf/
It is also important to inform you that inline Javascript is bad, you should reconsider your code when your Javascript skill will increase.
In order to solve the issue pointed out in the comments, you have to use some kind of counter and increment it when you hide the element, decrement it when you show element of one of his class, and displaying the associate element when this counter is 0.
This is also why you need two differentiated links: the "Remove" to increment, and the "Show" to decrement.
There are several way to implement this solution:
Use an associative array in Javascript
Use a custom attribute on the element
Add and remove specific classes
I chose the last one but this may be not the best one, this is just one of the possibilities.
https://jsfiddle.net/sy2mxscf/2/
The idea is to add or remove a custom "hidemeX" class. If you click on two different "Remove" links targeting the same element, two classes will be added. If you then click on any "Show" link, the associate class will be removed. But there is still a "hidemeX" class remaining until you click on the second link, so the element is not displayed thanks to CSS.
As Delgan says, its better to use class here, and you can use those <a>'s id as their class, so when you use your function swap, you can easily trace back to decide if the elements is selected, so the div should be removed.
Below is how you can separate javascript logic and html structure.
var swap = function(e) {
var close = 'Remove', open = 'Show';
var next = this.text === close ? open : close;
// Set the clicked <a>'s text.
this.text = next;
// Get divs that will affect by this <a>
var affectTarget = this.id;
// Affected div elements
var targets = document.getElementsByClassName(affectTarget);
var i, len = targets.length;
var visible;
var watch, wLen, j;
// For each <div> that will be affect by the clicked <a>, we have to chec :
for (i = 0; i < len; ++i) {
// Get the classes that used as a list to show which <a> will have a effect on it.
watch = targets[i].classList;
wLen = watch.length;
// visibilty is default to inline, if no <a> that it watches is selected, then it'll show
visible = "inline";
for (j = 0; j < wLen; ++j) {
// If any of the <a> it watches is selected, set the visibilty to none.
if (document.getElementById(watch[j]).text === open) {
visible = "none";
break;
}
}
targets[i].style.display = visible;
}
};
// For each switcher, we register a click event for it.
var switchers = document.querySelectorAll("a.showSwitcher");
var i, len = switchers.length;
for (i = 0; i < len; ++i) {
switchers[i].addEventListener('click', swap);
}
attribute a Remove
attribute b Remove
attribute c Remove
<hr/>
<div class="swaplinkA swaplinkB" style="display:inline">Element 1</div>
<div class="swaplinkA"style="display:inline">Element 2</div>
<div class="swaplinkA swaplinkC"style="display:inline">Element 3</div>

JavaScript - how to delete elements that do not have a specific class?

I want to delete all elements that do not have the class 'stay'
For example:
<div class="stay">Stay</div>
<div class="stay">Stay</div>
<div class="go">Go</div>
<div class="element">Stay</div>
<div class="Sel">classy</div>
I would like some javascript that would delete the elements that do not have the class stay and Sel, without having to list the classes go and element
I have used:
var els = document.querySelectorAll('#parent :not(.stay)');
for (var i = 0; i < els.length; i++) {
els[i].parentNode.removeChild(els[i])
}
from the first answer, but am unsure of how to keep the class 'Sel'.
Also, I DO NOT want any Jquery.
When you are doing such an operation should need to target a particular parent element, else it could also remove elements like html/body etc.
So assuming you have a parent node, you can use querySelectorAll in conjunction with :not() selector
<div id="parent">
<div class="stay">Stay</div>
<div class="stay">Stay</div>
<div class="go">Go</div>
<div class="element">element</div>
</div>
then
var els = document.querySelectorAll('#parent :not(.stay)');
for (var i = 0; i < els.length; i++) {
els[i].parentNode.removeChild(els[i])
}
Demo: Fiddle

About getElementById find multiple id name?

I have three id tag
<div id="view_1"></div>
<div id="view_2"></div>
<div id="view_3"></div>
I use getElementsByClassName way it can work
but "class" I take it to delimit css style
How could use document.getElementById find -> "view_1" "view_2" "view_3"
function hideDIV(){
var divs = document.getElementById('view'.*);
for(var i=0; i<divs.length; i++) {
divs[i].style.display='none';
}
}
You can do this:
var divs = document.getElementsByTagName("div");
for(var i = 0; i < divs.length; i++) {
if(divs[i].id.indexOf('view_') == 0) {
divs[i].style.display='none';
}
}
DEMO
Use QuerySelectorAll for that:
document.querySelectorAll('[id^="view_"]').id;
This will get all views that start with view_
See:
Javascript getElementById base on partial string
Try doing this : Fiddle
JS:
$('[id*="view"]').hide();
Html:
<div id="view_1"> dcf</div>
<div id="view_2"> DSg</div>
<div id="view_3"> gsde</div>
No, it won't work.
document.getElementById() method accepts only one argument.
However, you may always set classes to the elements and use getElementsByClassName() instead. Another option for modern browsers is to use querySelectorAll()method:
use $("div[id*='view']")
DEMO :http://jsfiddle.net/mkufymqr/1/
Vanilla JavaScript
document.querySelectorAll('div[id^="view_"]');
jQuery
$('div[id^="view_"]');
CSS 3
div[id^="view_"] { ... }
But consider using classes, not IDs, to semantically target elements.
Eg: search for all DIVs with the targetDiv class, and add the hidden class to them. Then define the hidden class as display: none in CSS.

javascript selectors

How does one select DOM elements in javascript?
Like for example:
<div class="des">
<h1>Test</h1>
<div class="desleft">
<p>Lorem Ipsum.</p>
</div>
<div class="Right">
<button>Test</button>
</div>
</div>
Now how do i select h1? This is just a part of a bigger Page, so cannot use getElementsByTagName(), since others might get selected. Also since there might be other h1's in the document later, i cannot attach the index(body's) to above.
Is there a simple way to select, say <h1> tag which is under the classname of desleft?
I cannot use jQuery or any other libraries.
You can use this to get to your H1:
var des = document.getElementsByClassName('des')
var fc = des[0].getElementsByTagName('h1')
alert(fc[0].innerHTML)
w3.org has selectors now (http://www.w3.org/TR/selectors-api/#examples). Here are 2 different ways that worked for me on Chrome. You may want to use querySelectorAll function that returns a list.
<script type="text/javascript">
//looks for <h1> tag under <div> with className "des"
showOff1 = function() {
var x = document.querySelector(".des h1");
alert(x.innerHTML);
}
//looks for <div> tag with className "desleft" and then use previousSibling to traceback <h1> tag
showOff2 = function() {
var y = document.querySelector("div.desleft");
var z = y.previousSibling.previousSibling;
alert(z.innerHTML);
}
</script>
<body onload="showOff2();">
Use querySelectorAll
You can use querySelectorAll:
// Will return a NodeList even if there is only one element found
var heading = document.querySelectorAll('.des > h1');
heading[1].style.color = 'red'; // NodeList is similar to an array
This will return a NodeList.
or
Use querySelector to return the first element found:
var first_heading = document.querySelector('.des > h1');
first_heading.style.color = 'blue';
Commonly used with an id selector #single-header-id.
Here's a demo
getElementsByTag()
Would be a function that you can start with, and then you can filter for the DOMElements that have the class.
var h1_array = document.getElementsByTag('h1');
var h1_class_array = [];
for (var i=0, len=h1_array.length; i < len; i++) {
if (h1_array[i].className.indexOf('classname') !== -1) {
h1_class_array.push(h1_array[i]);
}
}
The .indexOf function returns -1 if the needle is not found in the haystack.
Now re-reading your question, why not just give your h1's id's ?
DOM traversal is one of javascript's glaring issues (enter jQuery).
a simple getElementById() would save you a headache, and ids on all your h1's would be much cleaner in the end than trying to formulate an algorithm to select them by other means.
If you mean to select a h1 that is before the first element of class desleft, you could always do this:
document.getElementsByClassName("desleft")[0].previousSibling.previousSibling
Example: http://jsfiddle.net/Xeon06/ZMJJk/
previousSibling needs to be called twice because of the empty text node between the two. That's why using libraries to do this stuff is really the best way to go.
var h1 = document.querySelector('.desleft').previousElementSibling;
Find element with className='desleft' using selector '.desleft'
Just move back to previous element (not to previous node!)

Categories

Resources