How to Determine CSS selector on a DOM object? [duplicate] - javascript

This question already has answers here:
How to get an HTML element's style values in JavaScript?
(5 answers)
Get Element StyleSheet Style in JavaScript
(2 answers)
Closed 5 months ago.
I have an element such as element = document.getElementyById("myElement");
Now, let us assume that there is some CSS applied on it through various methods such as #id, .class, and tagName.
We know that #id has priority over .class and .class has priority over tagName. I want to determine which of the above method is applied on that element i.e. I want to see if is has CSS applied on it using id, class, or tag. How would I find that out? Is there any JavaScript Library available for that?

Go through the document.styleSheets object, iterate over each styleSheet object, then each rule. You will then have to parse the selectorText property, essentially writing your own CSS parser while maintaining an internal array on the specificity of each selector.
Compare the specificity of the current rule with the previous ones, then determine which property override which. After all that, you'll still need to check for inheritance - go through each of the parent of the element in question and look for properties that can be inherited, and add them to this list if they're not already set on the children. This also means that you'll need to maintain a set of properties that inherits.
If you haven't realised, this is quite an undertaking. Why not just go and use whatever developer tools that are available for your browser and look at the CSS rules provided by those instead.

Why dont you check
element = document.getElementyById("myElement");
if (element.tagName != "") { ... }
if (element.id != "") { ... }
if (element.className != "") { ... }

Related

select all items with class name using document.querySelector

I have 4 images using the class .light-image
I am trying to change them all using js. The code below only grabs the first item, how can I make it grab all 4?
if (window.matchMedia("(max-width: 768px)").matches) {
document.querySelector('.light-image').src="/app/themes/piranha/assets/public/images/light-open.svg";
}
Instead of querySelector use querySelectorAll that returns a node list of all elements matching the selector (not just the first one).
Then you need to iterate it over the node list.
if (window.matchMedia("(max-width: 768px)").matches) {
let itemList = [...document.querySelectorAll('.light-image')]
itemList.forEach(el => el.src="/app/themes/piranha/assets/public/images/light-open.svg";)
}
See this post for more information
querySelector vs querySelectorAll
Your current code works on the assumption that document.querySelector always returns a single (and non-null, non-undefined) HTMLImageElement object, whereupon your code immediately sets the .src property.
However, the querySelectorAll function returns a NodeList<TElement> object, which is an iterable collection of HTML elements instead of a singular nullable object reference.
If you're coming from a jQuery background you might be used to how jQuery's $('selector') function always returns a (wrapped) collection of elements, but it has an API design that allows you to set properties and call member functions on all elements in the collection as though the returned object represented a single element.
...unfortunately that style of API design (does it have a name?) doesn't apply anymore (good riddance...), so you need be familiar with how singular (scalar) object references compare to iterables.
In modern JavaScript, when you have an iterable collection you need to use for(of) to access, edit, and work with each object in the collection, like so:
(I changed your selector to img.light-image to prevent any non-<img/> elements from being inadvertently returned).
if (window.matchMedia("(max-width: 768px)").matches) {
const images = document.querySelectorAll('img.light-image'); // <-- `images: NodeList<HTMLImageElement>`
for( const img of images ) { // <-- `img: HTMLImageElement`
img.src = "/app/themes/piranha/assets/public/images/light-open.svg";
}
}
In old and obsolete (and especially non-portable) JavaScript, like from the days when we had to use jQuery, it was common to use the .forEach member function to succinctly iterate through a collection - however this is unwise, unsafe, and just passé now; namely because .forEach is not well-defined: for example, NodeList<T>.forEach is not standardized or in any formal specifications, according to the MDN.
A better idea:
Fun-fact: you don't need any JavaScript!
What you're trying to accomplish can be achieved using only CSS:
Remove your script and open your .css file (or inline <style> element) and put this instead:
See here: Is it possible to set the equivalent of a src attribute of an img tag in CSS?
#media screen and (max-width: 768px) {
img.light-image {
content: url("/app/themes/piranha/assets/public/images/light-open.svg")
}
}

JS how to get twitter's name [duplicate]

This question already has answers here:
How to Get Element By Class in JavaScript?
(12 answers)
Closed 9 years ago.
Using JavaScript, we can get element by id using following syntax:
var x=document.getElementById("by_id");
I tried following to get element by class:
var y=document.getElementByClass("by_class");
But it resulted into error:
getElementByClass is not function
How can I get an element by its class?
The name of the DOM function is actually getElementsByClassName, not getElementByClassName, simply because more than one element on the page can have the same class, hence: Elements.
The return value of this will be a NodeList instance, or a superset of the NodeList (FF, for instance returns an instance of HTMLCollection). At any rate: the return value is an array-like object:
var y = document.getElementsByClassName('foo');
var aNode = y[0];
If, for some reason you need the return object as an array, you can do that easily, because of its magic length property:
var arrFromList = Array.prototype.slice.call(y);
//or as per AntonB's comment:
var arrFromList = [].slice.call(y);
As yckart suggested querySelector('.foo') and querySelectorAll('.foo') would be preferable, though, as they are, indeed, better supported (93.99% vs 87.24%), according to caniuse.com:
querySelector(all)
getElementsByClassName
Don't use w3schools to learn something
Refer to MDN for accurate information
Another option is to use querySelector('.foo') or querySelectorAll('.foo') which have broader browser support than getElementsByClassName.
http://caniuse.com/#feat=queryselector
http://caniuse.com/#feat=getelementsbyclassname
You need to use the document.getElementsByClassName('class_name');
and dont forget that the returned value is an array of elements so if you want the first one use:
document.getElementsByClassName('class_name')[0]
UPDATE
Now you can use:
document.querySelector(".class_name") to get the first element with the class_name CSS class (null will be returned if non of the elements on the page has this class name)
or document.querySelectorAll(".class_name") to get a NodeList of elements with the class_name css class (empty NodeList will be returned if non of. the elements on the the page has this class name).
you can use
getElementsByClassName
suppose you have some elements and applied a class name 'test', so, you can get elements like as following
var tests = document.getElementsByClassName('test');
its returns an instance NodeList, or its superset: HTMLCollection (FF).
Read more

How to get all possible valid attributes on a DOM element [duplicate]

This question already has answers here:
How to list all element attributes in JS?
(3 answers)
Closed 5 years ago.
Please note that .attributes only gets the current attributes, which is not what this question is about.
I want a way to get all the attributes of a DOM element. Not just the ones that are on it now, but the ones that are possible in the future too.
The specific use case is to find the potential attributes in an SVGElement that aren't in an HTMLElement - there's a list on MDN (SVG Attribute reference), but, for obvious reasons, hardcoding is not a good idea.
My initial thought was to iterate through the prototype chain of an instance of each and compare the two lists (with basic filtering for event handlers), but this doesn't actually give the potential svg attributes.
EDIT
IMPORTANT NOTE - pasting your answer code into the console on this page and using document.body as a target should show a list of over 50 attributes, including things like contentEditable, contextMenu, dir, style, etc.
This also needs to work cross-browser.
Could something like this be what you're looking for?
It looks like a DOM element object stores empty keys for all possible attributes. Could you loop over these keys and store them in an array, then from there use something similar to filter out inherited attributes?
HTML
<svg id="blah"></svg>
Javascript
const blah = document.getElementById('blah')
let possibleKeys = []
for (let key in blah) {
possibleKeys.push(key)
}
Here's a JSBin example ... it looks like it produces a list of all possible attributes but it would need some filtering.
See also this thread.
How to list all element attributes in JS?
Any one of these should work because they return a live HTMLCollection.
var svgElement = window.document.getElementsByClassName("someSvgClass")[0];
//assume someSvgClass is on svg element.
//var svgElement = window.document.getElementsByTagName("svg")[0];
//var svgElement = window.document.getElementsByName("mySvg")[0];
//assume svg has this name.
var svgAttributes = svgElement.attributes;
for(let i=0; i<svgAttributes.length; i++) {
console.log(svgAttributes[i]);
}
See the below documentation from MDN on getElementsByTagName()
The Element.getElementsByTagName() method returns a live
HTMLCollection of elements with the given tag name. The subtree
underneath the specified element is searched, excluding the element
itself. The returned list is live, meaning that it updates itself with
the DOM tree automatically. Consequently, there is no need to call
several times Element.getElementsByTagName() with the same element and
arguments.
The documentation for getElementsByName , and getElementsByClassName say the same thing; a live node list is returned. If you'd like to try it, I created a fiddle here.
You'll see that svgAttributes list is automatically updated upon clicking "Add Attribute" without re-executing any of those functions.
There is no API for that and I don't think a workaround is possible because when you change an attribute on a current DOM node, the browser is responsible for re-rendering and updating the webpage in a low-level way that is not exposed to the JavaScript context.
Also, keep in mind that any correctly formatted attribute is actually valid in the context of a DOM tree, even though it might not trigger any change at the rendering level or in the way the browser renders the page. Especially the data-* attributes.
There might be some vendor-specific API but that wouldn't be useful if you want cross-browser compatibility.
You need to hardcode it, sadly. Given that you specifically want the SVGElement attributes, maybe you can scrape the W3's SVG standard document to automatically create the list?
Edit: I made a snippet to easily scrape the values from the standard:
const uniq = arr => Array.from(new Set(arr))
const nameElements = document.querySelectorAll('table[summary="Alphabetic list of attributes"] .attr-name')
const arrNameElements = Array.prototype.slice.call(nameElements)
const svgAttributes = uniq(arrNameElements.map(el => el.innerText.replace(/\‘|\’/g, '')))
Just execute it on the svg attributes page, by opening the dev console on the page and pasting in this code :)
Edit 2: I forgot the presentation attributes. I'll let you figure that one out ;)

Changing inner text value of tab through javascript

I'm learning Javascript right now, and attempting to change the text title of a particular tab. It's actually part of a larger Shiny dashboard project, but I want to add some custom functionality to a few tabs. Below are the tabs in question:
Simple enough. I first access my tabs in my Javascript file:
var tabScrub2 = $(document).find('[data-value="scrubTab2"]');
console.log(tabScrub2);
When I use Firefox's developer console, I see that the tab is an object:
Moreover, it looks like I need to change the innerText property of 0, whatever this is, since that corresponds to the title of my tab (the innerText of 1 corresponds to the text inside scrubTab2). However, I'm not familiar with the actual object type being returned here:
Simply put, how the heck do I access and manipulate properties from this? And am I actually accessing an array? When I type in
var scrub2 = tabScrub2["1"];
console.log(scrub2);
I get an HTML element. I'm seen the a element in CSS and jQuery, but am not super familiar with how to manipulate its properties programmatically? How do I go about accessing and manipulating the innerText properties of this via Javascript? For instance, how would I hide scrubTab2, or change its title to something else?
The first object you're seeing is jQuery's wrapper around the real DOM elements. It's not an actual array, but it does contain all of the elements that matched your query under zero-indexed properties (e.g. "0" and "1") which allows you to access to them via an array-like API (e.g. tabScrub[1]).
Your method of grabbing a node using tabScrub2["1"] is correct (see this question in the jQuery FAQ). It's more likely to see that done with a numeric key though (i.e. tabScrub[1]) because that matches the way you would access an element in a normal array.
As far as manipulating properties of the DOM node, the DOM's API is notoriously inconsistent and quirky (hence the need for things like jQuery in the first place). However, for your use case you can just assign a string to the innerText property directly (e.g. tagScrub2[1].innerText = "Tab title"). MDN is a great resource if you're looking for reference material on other parts of the DOM.
A side note: if you're looking for a specific element you should use a query that will only match that element. It's generally a bad sign if you're grabbing extra elements and then accessing the element you want at a key other than 0. If you're doing this then your code depends on other (potentially unrelated) nodes in the DOM existing before your node, and if/when you change those nodes your original code will break.
Just use jQuery eq method to get the relevant object index from the array.
For an example
//Query and get first element.
var tabScrub2 = $(document).find('[data-value="scrubTab2"]:eq(0)');
//Hide
tabScrub2.hide();
//Change title
tabScrub2.attr("title", "New Title Text");
Lean more about jQuery eq here.
https://api.jquery.com/eq/
Since you use jquery selectors tabScrub2[0] returns the native DOM element instead of another jQuery object. Therefore the hide function won't work in that object since the native DOM element doesn't implement such type of functionality for an element. That's why you have to use jQuery pseudo selector as above. Because hide will only work with a jQuery object.

Javascript incapable of getting element's max-height via element.style.maxHeight [duplicate]

This question already has answers here:
How to get an HTML element's style values in JavaScript?
(5 answers)
Closed 8 years ago.
I am making a simple accordion menu in javascript. I'd like to be able to set the compact and expanded heights for the elements via the css max-height and min-height values. For some reason, when I try to retrieve the min-height and max-height of the elements in javascript for animation purposes, I get an empty string rather than, for instance, "500px" like it should. The max-height value is set in css, e.g.
#id {
min-height: 40px;
max-height: 500px;
}
is all set up, but when I put a debugging mechanism in my javascript such as
alert( item.style.minHeight );
it pops up an empty alert box. This happens in Firefox 3.6.2 and IE 8. Does anybody know why javascript refuses to be able to get an element's minHeight and maxHeight?
The element.style property lets you know only the CSS properties that were defined as inline in that element, you should get the computed style, is not so easy to do it in a cross-browser way, as others said, IE has its own way, through the element.currentStyle property, the DOM Level 2 standard way, implemented by other browsers is the document.defaultView.getComputedStyle method.
However there are differences between the IE way and the standard way, for example, the IE element.currentStyle property expect that you access the CCS property names composed of two or more words in camelCase (e.g. maxHeight, fontSize, backgroundColor, etc), the standard way expects the properties with the words separated with dashes (e.g. max-height, font-size, background-color, etc).
Also, the IE element.currentStyle will return all the sizes in the unit that they were specified, (e.g. 12pt, 50%, 5em), the standard way will compute the actual size in pixels.
I made some time ago a cross-browser function that allows you to get the computed styles in a cross-browser way:
function getStyle(el, styleProp) {
var value, defaultView = (el.ownerDocument || document).defaultView;
// W3C standard way:
if (defaultView && defaultView.getComputedStyle) {
// sanitize property name to css notation
// (hypen separated words eg. font-Size)
styleProp = styleProp.replace(/([A-Z])/g, "-$1").toLowerCase();
return defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
} else if (el.currentStyle) { // IE
// sanitize property name to camelCase
styleProp = styleProp.replace(/\-(\w)/g, function(str, letter) {
return letter.toUpperCase();
});
value = el.currentStyle[styleProp];
// convert other units to pixels on IE
if (/^\d+(em|pt|%|ex)?$/i.test(value)) {
return (function(value) {
var oldLeft = el.style.left, oldRsLeft = el.runtimeStyle.left;
el.runtimeStyle.left = el.currentStyle.left;
el.style.left = value || 0;
value = el.style.pixelLeft + "px";
el.style.left = oldLeft;
el.runtimeStyle.left = oldRsLeft;
return value;
})(value);
}
return value;
}
}
The above function is not perfect for some cases, for example for colors, the standard method will return colors in the rgb(...) notation, on IE they will return them as they were defined.
Check this example.
currentStyle for IE, getComputedStyle elsewhere.
document.defaultView.getComputedStyle(who,'').getPropertyValue('min-height');
Might as well learn it, IE 9 will support getComputedStyle.
You need to use currentStyle instead...
alert(item.currentStyle.minHeight);
The style property refers to what has been set by Javascript, as opposed to the inherited CSS. Libraries like jQuery address this internally (among other countless annoyances).
I highly recommend jQuery.
Just add jQuery to your page, then you can get and set CSS attributes dynamically and in a cross browser way (it eliminates a LOT of headaches). Here's the syntax:
/* this outer '$(function() { innerContent });'
is jQuery's helpful function that executes when all
the elements in your HTML document are ready to
be accessed (if you executed code without this,
when you try to find the element you want to find,
it might not have been created yet, and so your code
will have no effect on that element) */
$(function() {
// get CSS data
var currentMinHeight = $('#idOfElement').css('min-height');
var currentMaxHeight = $('#idOfElement').css('max-height');
// set CSS data
$('#idOfElement').css('min-height', '999px');
$('#idOfElement').css('max-height', '999px');
});
Be sure not to forget the # in front of the element's id (this is how jQuery knows you want the element that has that id)
There are ways you avoid the redundant function calls I made above and accomplish the same thing. jQuery.com will get you rolling like a cross browser pro in no time!

Categories

Resources