javascript getElementsByClassName("foo"||"bar") - javascript

Basically I want a snippet of javascript to add the height of the browser window to any elements with either of the classes fullscreen or fullheight
function fullsize(){
var a = document.getElementsByClassName("fullscreen"),
b = document.getElementsByClassName("fullheight");
for (var i=0; i<a.length; i++){
a[i].style.height = window.innerHeight + "px";
}
for (var j=0; j<b.length; j++){
b[j].style.height = window.innerHeight + "px";
}
}
window.addEventListener("load", fullsize),
window.addEventListener("resize", fullsize);
This (above) works perfectly well, I was just wondering if there was any way to condense it into just one for(){...} like the jQuery equiv.
function fullsizes(){
$(".fullheight,.fullscreen").each(function(){
$(this).height($(window).height())
})
}

You can use document.querySelectorAll
Returns a list of the elements within the document (using depth-first pre-order traversal of the document's nodes) that match the specified group of selectors. The object returned is a NodeList.
Code example
document.querySelectorAll(".fullscreen, .fullheight");
Change your to code
function fullsize(){
var a = document.querySelectorAll(".fullscreen, .fullheight");
for (var i=0; i<a.length; i++){
a[i].style.height = window.innerHeight + "px";
}
}

If you really have to use javascript instead of writing some css
style.css:
.fullscreen, .fullheight {
height: 100vh;
}
You can use document.querySelectorAll like Satpal said.

You can use querySelector() or querySelectorAll() to do this:
querySelector
Returns the first matching Element node within the node's subtree. If no matching node is found, null is returned.
querySelectorAll
Returns a NodeList containing all matching Element nodes within the node's subtree, or an empty NodeList if no matches are found.
You might also find the following website useful; it contains examples of how you can do jQuery-like things without using jQuery: http://youmightnotneedjquery.com/

You can merge arrays with the concat method
var c = a.concat(b)
And then you can iterate over c instead.

Related

Two blocks in getElementById [duplicate]

doStuff(document.getElementById("myCircle1" "myCircle2" "myCircle3" "myCircle4"));
This doesn't work, so do I need a comma or semi-colon to make this work?
document.getElementById() only supports one name at a time and only returns a single node not an array of nodes. You have several different options:
You could implement your own function that takes multiple ids and returns multiple elements.
You could use document.querySelectorAll() that allows you to specify multiple ids in a CSS selector string .
You could put a common class names on all those nodes and use document.getElementsByClassName() with a single class name.
Examples of each option:
doStuff(document.querySelectorAll("#myCircle1, #myCircle2, #myCircle3, #myCircle4"));
or:
// put a common class on each object
doStuff(document.getElementsByClassName("circles"));
or:
function getElementsById(ids) {
var idList = ids.split(" ");
var results = [], item;
for (var i = 0; i < idList.length; i++) {
item = document.getElementById(idList[i]);
if (item) {
results.push(item);
}
}
return(results);
}
doStuff(getElementsById("myCircle1 myCircle2 myCircle3 myCircle4"));
This will not work, getElementById will query only one element by time.
You can use document.querySelectorAll("#myCircle1, #myCircle2") for querying more then one element.
ES6 or newer
With the new version of the JavaScript, you can also convert the results into an array to easily transverse it.
Example:
const elementsList = document.querySelectorAll("#myCircle1, #myCircle2");
const elementsArray = [...elementsList];
// Now you can use cool array prototypes
elementsArray.forEach(element => {
console.log(element);
});
How to query a list of IDs in ES6
Another easy way if you have an array of IDs is to use the language to build your query, example:
const ids = ['myCircle1', 'myCircle2', 'myCircle3'];
const elements = document.querySelectorAll(ids.map(id => `#${id}`).join(', '));
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:
document.querySelectorAll("#myCircle1, #myCircle2, #myCircle3, #myCircle4");
I suggest using ES5 array methods:
["myCircle1","myCircle2","myCircle3","myCircle4"] // Array of IDs
.map(document.getElementById, document) // Array of elements
.forEach(doStuff);
Then doStuff will be called once for each element, and will receive 3 arguments: the element, the index of the element inside the array of elements, and the array of elements.
getElementByID is exactly that - get an element by id.
Maybe you want to give those elements a circle class and getElementsByClassName
document.getElementById() only takes one argument. You can give them a class name and use getElementsByClassName() .
Dunno if something like this works in js, in PHP and Python which i use quite often it is possible.
Maybe just use for loop like:
function doStuff(){
for(i=1; i<=4; i++){
var i = document.getElementById("myCiricle"+i);
}
}
Vulgo has the right idea on this thread. I believe his solution is the easiest of the bunch, although his answer could have been a little more in-depth. Here is something that worked for me. I have provided an example.
<h1 id="hello1">Hello World</h1>
<h2 id="hello2">Random</h2>
<button id="click">Click To Hide</button>
<script>
document.getElementById('click').addEventListener('click', function(){
doStuff();
});
function doStuff() {
for(var i=1; i<=2; i++){
var el = document.getElementById("hello" + i);
el.style.display = 'none';
}
}
</script>
Obviously just change the integers in the for loop to account for however many elements you are targeting, which in this example was 2.
The best way to do it, is to define a function, and pass it a parameter of the ID's name that you want to grab from the DOM, then every time you want to grab an ID and store it inside an array, then you can call the function
<p id="testing">Demo test!</p>
function grabbingId(element){
var storeId = document.getElementById(element);
return storeId;
}
grabbingId("testing").syle.color = "red";
You can use something like this whit array and for loop.
<p id='fisrt'>??????</p>
<p id='second'>??????</p>
<p id='third'>??????</p>
<p id='forth'>??????</p>
<p id='fifth'>??????</p>
<button id="change" onclick="changeColor()">color red</button>
<script>
var ids = ['fisrt','second','third','forth','fifth'];
function changeColor() {
for (var i = 0; i < ids.length; i++) {
document.getElementById(ids[i]).style.color='red';
}
}
</script>
For me worked flawles something like this
doStuff(
document.getElementById("myCircle1") ,
document.getElementById("myCircle2") ,
document.getElementById("myCircle3") ,
document.getElementById("myCircle4")
);
Use jQuery or similar to get access to the collection of elements in only one sentence. Of course, you need to put something like this in your html's "head" section:
<script type='text/javascript' src='url/to/my/jquery.1.xx.yy.js' ...>
So here is the magic:
.- First of all let's supose that you have some divs with IDs as you wrote, i.e.,
...some html...
<div id='MyCircle1'>some_inner_html_tags</div>
...more html...
<div id='MyCircle2'>more_html_tags_here</div>
...blabla...
<div id='MyCircleN'>more_and_more_tags_again</div>
...zzz...
.- With this 'spell' jQuery will return a collection of objects representing all div elements with IDs containing the entire string "myCircle" anywhere:
$("div[id*='myCircle']")
This is all! Note that you get rid of details like the numeric suffix, that you can manipulate all the divs in a single sentence, animate them... Voilá!
$("div[id*='myCircle']").addClass("myCircleDivClass").hide().fadeIn(1000);
Prove this in your browser's script console (press F12) right now!
As stated by jfriend00,
document.getElementById() only supports one name at a time and only returns a single node not an array of nodes.
However, here's some example code I created which you can give one or a comma separated list of id's. It will give you one or many elements in an array. If there are any errors, it will return an array with an Error as the only entry.
function safelyGetElementsByIds(ids){
if(typeof ids !== 'string') return new Error('ids must be a comma seperated string of ids or a single id string');
ids = ids.split(",");
let elements = [];
for(let i=0, len = ids.length; i<len; i++){
const currId = ids[i];
const currElement = (document.getElementById(currId) || new Error(currId + ' is not an HTML Element'));
if(currElement instanceof Error) return [currElement];
elements.push(currElement);
};
return elements;
}
safelyGetElementsByIds('realId1'); //returns [<HTML Element>]
safelyGetElementsByIds('fakeId1'); //returns [Error : fakeId1 is not an HTML Element]
safelyGetElementsByIds('realId1', 'realId2', 'realId3'); //returns [<HTML Element>,<HTML Element>,<HTML Element>]
safelyGetElementsByIds('realId1', 'realId2', 'fakeId3'); //returns [Error : fakeId3 is not an HTML Element]
If, like me, you want to create an or-like construction, where either of the elements is available on the page, you could use querySelector. querySelector tries locating the first id in the list, and if it can't be found continues to the next until it finds an element.
The difference with querySelectorAll is that it only finds a single element, so looping is not necessary.
document.querySelector('#myCircle1, #myCircle2, #myCircle3, #myCircle4');
here is the solution
if (
document.getElementById('73536573').value != '' &&
document.getElementById('1081743273').value != '' &&
document.getElementById('357118391').value != '' &&
document.getElementById('1238321094').value != '' &&
document.getElementById('1118122010').value != ''
) {
code
}
You can do it with document.getElementByID Here is how.
function dostuff (var here) {
if(add statment here) {
document.getElementById('First ID'));
document.getElementById('Second ID'));
}
}
There you go! xD

replace all elements belonging to a specific class

I was trying to develop an embedded widget. User would include an anchor tag and a javascript in their page, and it would render the content. Similar to embedded tweets.
<a href="http://localhost:3000/user/13"
target="_blank"
class="my-widget"
data-widget-type="profile"
data-widget-identifier="id"
data-identifier-value="13"
>Sayantan Das</a>
</div>
<script src="//localhost/my-widget/js/widget.js" async ></script>
And from widget.js, i would get all the elements with class="my-widget" and replace with an iframe.
widgets.js
!function(global, document) {
global.MyWidgets = global.MyWidgets || {};
for(let widgets = document.getElementsByClassName('my-widget'), i = 0; i < widgets.length; i++) {
console.log(widgets)
let element = widgets[i];
let span = document.createElement('span');
span.innerHTML = "Changed from widget " + i;
element.parentNode.appendChild(span);
element.parentNode.removeChild(element);
}
}(window, document);
The problem is , when I remove the element the loop also runs for a shorter number. for example, if there are two elements with class my-widget, after first time the loop runs and one element is removed and the loop runs only once. How do I replace all the elements?
That's because getElementsByClassName returns a live HTMLCollection; when you remove the class="my-widget" element from the DOM, it's also removed from the collection.
Either work backward through the collection (so you're removing from the end, which doesn't affect the ones before it), or use querySelectorAll(".my-widget") instead, which returns a snapshot NodeList, not a live HTMLCollection.
Working backward:
for(let widgets = document.getElementsByClassName('my-widget'), i = widgets.length - 1; i >= 0; i--) {
Using qSA instead:
for(let widgets = document.querySelectorAll('.my-widget'), i = 0; i < widgets.length; i++) {
or if you don't need i (you seem only to be using it to get the element and for demo purposes), you can use for-of with NodeLists now (on most platforms; this answer has a polyfill for others):
for (const element of document.querySelectorAll('.my-widget')) {
// ...and remove the `let element = ...` line
use document.querySelectorAll to the length of the widgets

Change class style in js

I want to change the style of a class, I know this is a pretty simple question but already tried google and cant find how to do it, this is my code but its not working I get Syntax error
$(window).scroll(function() {
if ($(this).scrollTop()> 620) {
document.getElementsByClassName("advanced-search").style.position = ¨sticky;¨
$('.advanced-search').fadeIn();
}
document.getElementsByClassName returns and HTMLCollection which is an array-like obbject. It will not have .style.position properties. Since you are already using jQuery just query the selector using that.
var $el = $('.advanced-search');
$el.css('position', 'fixed');
$el.fadeIn();
From MDN, emphasis mine:
Returns an array-like object of all child elements which have all of the given class names.
style is not a property of a list; you must either iterate through each element and apply style or select an element out of the list.
One way to do this would be to turn the result of getElementsByClassName into an array an iterate over it:
var advSearches = document.getElementsByClassName('advanced-search');
advSearches = Array.prototype.slice.call(advSearches);
advSearches.forEach(function(element) {
element.style.position = 'sticky';
});
Or, condensed with ES6 destructuring:
[...document.getElementsByClassName('advanced-search')]
.map(e => e.style.position = 'sticky');
document.getElementsByClassName("advanced-search") is an array and you can't straightly add styles to all of them entirely just like that way you've used!
use for loop or foreach
$(window).scroll(function() {
if ($(this).scrollTop()> 620) {
var x = document.getElementsByClassName("advanced-search");
for(var i=0;i<x.length;i++){
x[i].style.position = ¨sticky;¨
}
$('.advanced-search').fadeIn();
}
});

How to remove a class from elements in pure JavaScript?

I would like to know how to select all elements with class names "widget" and "hover" and then remove class "hover" from these elements.
I have the following JavaScript code that selects all elements with class "widget" and "hover":
var elements = document.getElementsByClassName('widget hover');
console.log(elements);
This seems to work and outputs something like this (with no errors):
[div#.widget...
The problem is that if I try to remove the class "hover", I get an error:
var elements = document.getElementsByClassName('widget hover');
console.log(elements);
elements.classList.remove("hover");
This outputs:
[item: function]
length: 0
Uncaught TypeError: Cannot call method 'remove' of undefined
Can anyone tell me what I'm doing wrong?
Please note that I have it working in jQuery:
$('.widget.hover').removeClass('hover');
... but I'm looking for a solution in pure JavaScript.
var elems = document.querySelectorAll(".widget.hover");
[].forEach.call(elems, function(el) {
el.classList.remove("hover");
});
You can patch .classList into IE9. Otherwise, you'll need to modify the .className.
var elems = document.querySelectorAll(".widget.hover");
[].forEach.call(elems, function(el) {
el.className = el.className.replace(/\bhover\b/, "");
});
The .forEach() also needs a patch for IE8, but that's pretty common anyway.
It's 2023... keep it simple and just use es6
Times have changed and now the cleanest and most readable way to do this is:
Array.from(document.querySelectorAll('.widget.hover')).forEach((el) => el.classList.remove('hover'));
If you can't support arrow functions then just convert it like this:
Array.from(document.querySelectorAll('.widget.hover')).forEach(function(el) {
el.classList.remove('hover');
});
Additionally if you need to support extremely old browsers then use a polyfil for the forEach and Array.from and move on with your life.
Find elements:
var elements = document.getElementsByClassName('widget hover');
Since elements is a live array and reflects all dom changes you can remove all hover classes with a simple while loop:
while(elements.length > 0){
elements[0].classList.remove('hover');
}
Elements is an array of DOM objects. You should do something like this:
for (var i = 0; i < elements.length; i++) {
elements[i].classList.remove('hover');
}
Enumerate the elements collection and for each element inside the collection call the remove method
For ES6, this can be done in a few ways with one liners, where you create an array of the elements with the spread operator ..., and remove the class with the map operator:
With querySelectorAll:
[...document.querySelectorAll('.widget')].map(x => x.classList.remove('hover'));
With getElementsByClassName:
[...document.getElementsByClassName('widget')].map(x => x.classList.remove('hover'));
For querySelectorAll, notice the use of .widget instead of widget. An alternative for the spread operator would be to use Array.from like:
Array.from(document.querySelectorAll('.widget')).map(x => x.classList.remove('hover'));
This might help:
let allElements = Array.from(document.querySelectorAll('.widget.hover'));
for (let element of allElements) {
element.classList.remove('hover');
}
I use a simple method.
If you always process [0] in the required number of loops, you can apply the process to all.
The HTMLCollection(elements) changes in real time, so put the length in a variable. (l = element.length)
for(var elements = document.getElementsByClassName('widget hover'), i = 0, l = elements.length; l > i; i++) {
elements[0].classList.remove("hover");
}
var elems = document.querySelectorAll(".widget.hover");
for(let elem of elems){
elem.classList.remove('hover');
}
Given worked for me.
document.querySelectorAll(".widget.hover").forEach(obj=>obj.classList.remove("hover"));

ID Ends With in pure Javascript

I am working in a Javascript library that brings in jQuery for one thing: an "ends with" selector. It looks like this:
$('[id$=foo]')
It will find the elements in which the id ends with "foo".
I am looking to do this without jQuery (straight JavaScript). How might you go about this? I'd also like it to be as efficient as reasonably possible.
Use querySelectorAll, not available in all browsers (like IE 5/6/7/8) though. It basically works like jQuery:
http://jsfiddle.net/BBaFa/2/
console.log(document.querySelectorAll("[id$=foo]"));
You will need to iterate over all elements on the page and then use string functions to test it. The only optimizations I can think of is changing the starting point - i.e. not document.body but some other element where you know your element will be a child of - or you could use document.getElementsByTagName() to get an element list if you know the tag name of the elements.
However, your task would be much easier if you could use some 3rd-party-javascript, e.g. Sizzle (4k minified, the same selector engine jQuery uses).
So, using everything that was said, I put together this code. Assuming my elements are all inputs, then the following code is probably the best I am going to get?
String.prototype.endsWith = function(suffix) {
return this.indexOf(suffix, this.length - suffix.length) !== -1;
};
function getInputsThatEndWith(text) {
var result = new Array();
var inputs = document.getElementsByTagName("input");
for(var i=0; i < inputs.length; i++) {
if(inputs[i].id.endsWith(text))
result.push(inputs[i]);
}
return result;
}
I put it on JsFiddle: http://jsfiddle.net/MF29n/1/
#ThiefMaster touched on how you can do the check, but here's the actual code:
function idEndsWith(str)
{
if (document.querySelectorAll)
{
return document.querySelectorAll('[id$="'+str+'"]');
}
else
{
var all,
elements = [],
i,
len,
regex;
all = document.getElementsByTagName('*');
len = all.length;
regex = new RegExp(str+'$');
for (i = 0; i < len; i++)
{
if (regex.test(all[i].id))
{
elements.push(all[i]);
}
}
return elements;
}
}
This can be enhanced in a number of ways. It currently iterates through the entire dom, but would be more efficient if it had a context:
function idEndsWith(str, context)
{
if (!context)
{
context = document;
}
...CODE... //replace all occurrences of "document" with "context"
}
There is no validation/escaping on the str variable in this function, the assumption is that it'll only receive a string of chars.
Suggested changes to your answer:
RegExp.quote = function(str) {
return str.replace(/([.?*+^$[\]\\(){}-])/g, "\\$1");
}; // from https://stackoverflow.com/questions/494035/#494122
String.prototype.endsWith = function(suffix) {
return !!this.match(new RegExp(RegExp.quote(suffix) + '$'));
};
function getInputsThatEndWith(text) {
var results = [],
inputs = document.getElementsByTagName("input"),
numInputs = inputs.length,
input;
for(var i=0; i < numInputs; i++) {
var input = inputs[i];
if(input.id.endsWith(text)) results.push(input);
}
return results;
}
http://jsfiddle.net/mattball/yJjDV/
Implementing String.endsWith using a regex instead of indexOf() is mostly a matter of preference, but I figured it was worth including for variety. If you aren't concerned about escaping special characters in the suffix, you can remove the RegExp.quote() bit, and just use
new RegExp(suffix + '$').
If you know the type of DOM elements you are targeting,
then get a list of references to them using getElementsByTagName , and then iterate over them.
You can use this optimization to fasten the iterations:
ignore the elements not having id.
target the nearest known parent of elements you want to seek, lets say your element is inside a div with id='myContainer', then you can get a restricted subset using
document.getElementById('myContainer').getElementsByTagName('*') , and then iterate over them.

Categories