Selecting first visible element with classname [duplicate] - javascript

This question already has answers here:
Getting first visible element with jQuery
(3 answers)
Closed 3 years ago.
I'm trying to select the first element with a specific class that is also visible. I only want to select the one element and store it as a variable.
var elements = document.getElementsByClassName('className'); // Get all visible elements with classname.
var element= elements[0]; // Return only the first element from this NodeList
For my specific use case, I'm attempting to then retrieve its background image, so this is what I've got so far. My variable returns "undefined".
var bg = element.css('background-image'); // Returns url('http://www.google.com/imageurl')
I'm using jQuery, but plain JavaScript is welcome, too. Whatever gets the job done the best.

Here's what I would do using JQuery:
var element = $(".classname:visible:first");
var bg = element.css('background-image');
element contains the first element of the specified classname that is visible.

You could use the :visible selector. Something like this $('.classname:visible') .
https://api.jquery.com/visible-selector/

$('selector:visible') will get you visible elements matching the given selector
.eq(n) will return the nth node from those matched
.css('backgroundImage') will give you the background image
.match(/"(.+)"/)[1] will then return just the URL of the background image:
var specialElement = $('.example:visible').eq(1);
specialElement.append(specialElement.css('backgroundImage').match(/"(.+)"/)[1]);
body {
color: white;
}
.example {
visibility: hidden;
}
.special {
visibility: visible;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<head>
<title>example</title>
</head>
<body>
<header>
<h1>Hello World</h1>
</header>
<main>
<section>
<article class="example" style="background-image:url('https://images.pexels.com/photos/374815/pexels-photo-374815.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500');">
<h2>Bananas</h2>
<p>Bananas are a great source of potassium.</p>
</article>
<article class="example special" style="background-image:url('https://images.pexels.com/photos/707194/pexels-photo-707194.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500');">
<h2>Apples</h2>
<p>An apple a day will keep the doctor away!</p>
</article>
<article class="example" style="background-image:url('https://images.pexels.com/photos/1667580/pexels-photo-1667580.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500');">
<h2>Oranges</h2>
<p>Oranges make great juice.</p>
</article>
</section>
</main>
</body>

Related

Create highlight effect on hover an element

I tried to make highlight effect on each <a> element while I hover on each div element but it doesn't work and console shows this error
"Uncaught TypeError: Cannot set property 'background' of undefined
at highlight_function"
enter image description here
function highlight_function () {document.getElementsByTagName("a").style.background="#80ff00"};
document.getElementsByTagName("div").addEventListener("mouseover",highlight_function())
I think it's because document.getElementsByTagName("a") is an array, and you are trying to set style on the array and not in each element.
You should either make a for loop to change background style of each element or add a style tag like a {background: "#80ff00"}.
But you can't define style to an array like this
index.html
<html lang="en">
<head>
</head>
<body>
<div>
something
</div>
</body>
<script>
function highlight_function() {
const a = document.querySelector('a');
a.style.background = "#80ff00"
}
const div = document.querySelector('div');
div.addEventListener('mouseover', highlight_function);
</script>
</html>
I don't think background property will work on an <a> tag. Try doing this in your function:
document.getElementsByTagName("a").style.color="#80ff00"
Here is you can try this
function highlight_function() {
document.getElementById("a").style.backgroundColor = "#80ff00";
};
<div id="div">
<a id="a" onmouseover="highlight_function()">Hell</a>
</div>
when you make this call
document.getElementsByTagName("a")
it will return to you collection of html elements so there is no style property
you can use for loop through it
for(var a of document.getElementsByTagName("a")) {
a.style.background="#80ff00";
}
you can simply add highlight effect or change the background color by adding the CSS as follows:
<!DOCTYPE html>
<html>
<head>
<style>
p:hover {
background-color: green;
}
</style>
</head>
<body>
<p id="hometown">I live in Pakistan</p>
</body>
</html>

javascript flipping divs with the same class name horizontaly

I have a bunch of divs like this:
What I would like to do is flip the divs, so the first element becomes the last and the last element becomes first, essentially flipping divs around so 1element,2element,3element would become 3element, 2element, 1element.
I am not sure if this is even possible as there is nothing to distinguish those divs as they all have the same id and class name.
This question is similar to this one: Javascript only - sort a bunch of DIVs
except that here divs have the same id, class name so it makes it all harder.
You can first get all elements with your class, convert it into an array and call reverse() function that flips the array, then loop through the reversed array and append children back to your target div.
Sample codes
<!DOCTYPE html>
<html>
<head>
<title>Parcel Sandbox</title>
<meta charset="UTF-8" />
</head>
<body>
<div>
Original:
<div class="test">1</div>
<div class="test">2</div>
<div class="test">3</div>
<div class="test">4</div>
<div class="test">5</div>
</div>
<br />
<div id="target">
Reversed:
<!-- Will be created with Javascript -->
</div>
<script>
const reversedDivs = Array.from(document.getElementsByClassName("test")).reverse();
const targetDiv = document.getElementById("target");
// Create another list in reversed order
reversedDivs.forEach(div => {
const newDiv = div.cloneNode(true);
targetDiv.appendChild(newDiv);
})
</script>
</body>
</html>
Here's a working example: https://codesandbox.io/s/html-reverse-list-u3kld?fontsize=14&hidenavigation=1&theme=dark
...as there is nothing to distinguish those divs as they all have the same id and class name...
Ah, but there is! Where they are in their parent. You can get an array of the elements, reverse it, and then append them to the parent, which will move them so that they're in that reverse order:
var container = document.getElementById("container");
var divs = Array.from(container.children);
divs.reverse();
divs.forEach(function(div) {
container.appendChild(div);
});
Live Example:
setTimeout(function() {
var container = document.getElementById("container");
var divs = Array.from(container.children);
divs.reverse();
divs.forEach(function(div) {
container.appendChild(div);
});
}, 800);
.ib {
display: inline-block;
}
<div id="container"><div class="ib">1</div><div class="ib">2</div><div class="ib">3</div><div class="ib">4</div><div class="ib">5</div></div>
Note that I was careful to do the markup so that there wouldn't be any Text nodes in there, because the children collection only includes Elements, not Text nodes. But if you want to reverse all the children, including text nodes, use childNodes instead of children:
setTimeout(function() {
var container = document.getElementById("container");
var divs = Array.from(container.childNodes);
divs.reverse();
divs.forEach(function(div) {
container.appendChild(div);
});
}, 800);
.ib {
display: inline-block;
}
<div id="container">
<div class="ib">1</div>
<div class="ib">2</div>
<div class="ib">3</div>
<div class="ib">4</div>
<div class="ib">5</div>
</div>
Note that I've kept the code to ES5 level (not ES2015+), except that Array.from is more recent. You can easily polyfill it, or use
var divs = Array.prototype.slice.call(container.children/*or childNodes*/);
instead.

Targeting DOM Nodes Isn't Quite Working

The following HTML markup and script is faulty, but I'm not getting why:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>More Ways To Target Elements</title>
</head>
<body>
<div id="div1">
<div id div="div2">
<p id="p1">Chicago</p>
<p>Kansas City</p>
<p>St. Louis</p>
</div>
</div>
<script>
var div = document.getElementById('div2');
for (var i = 0; i < div.childNodes.length; i++) {
if (div.childNodes[i].childNodes[0].nodeType === 3) {
alert(div.childNodes[i].childNodes[0].innerHTML);
}
}
</script>
</body>
</html>
I tried minifying the whole thing but I get the same results from the console, which says:
Uncaught TypeError: Cannot read property 'childNodes' of null
Any suggestions, anyone?
There are a few problems there:
Your HTML is invalid and you have no element with the id div2 (<div id div="div2"> should be <div id="div2">). That's what's causing the error you're starting out with.
But once you fix it, you'll run into more errors:
Not all nodes have childNodes, only Element nodes do. Specifically, Text nodes do not. But you're assuming all of the child nodes of #div2 are Element nodes. They aren't, some are Text nodes.
If you only want to look at Element nodes in #div2, use div.children rather than div.childNodes. children only contains Elements, not other kinds of nodes.
You're assuming all of the children of #div2 have at least one child node, because (if you implement #2 above) you're doing div.children[i].childNodes[0].nodeType. That will throw an exception if there are no child nodes, because childNodes[0] will give you undefined and you can't read .nodeType from undefined. You need a guard there.
Text nodes don't have innerHTML. If you want the text of a Text node, you use nodeValue.
With those changes:
var div = document.getElementById('div2');
for (var i = 0; i < div.children.length; i++) {
if (div.children[i].childNodes[0]) {
alert(div.children[i].childNodes[0].nodeValue);
}
}
<div id="div1">
<div id="div2">
<p id="p1">Chicago</p>
<p>Kansas City</p>
<p>St. Louis</p>
</div>
</div>
But, if the goal is to show the text content of the children of #div2, I'd probably use querySelectorAll and use textContent (not supported on older IE) or innerText on the elements (which are not the same thing, but the differences don't matter here) instead, as it would be simpler:
// Get the name to use (textContent isn't supported on older IE)
var propName = "textContent" in document.body ? "textContent" : "innerText";
// Get the immediate children of #div2,
// alert their contents
var list = document.querySelectorAll('#div2 > *');
for (var i = 0; i < list.length; i++) {
alert(list[i][propName]);
}
<div id="div1">
<div id="div2">
<p id="p1">Chicago</p>
<p>Kansas City</p>
<p>St. Louis</p>
</div>
</div>

How to change the colour of a div element when clicked?

I have a this html page, Whenever the element with class name FreeSeat is clicked I want to change the colour of that div element.Below is my html page
<html>
<head>
<title>
QuickBus
</title>
<link type="text/css" rel="stylesheet" href="Seat.css">
</head>
<body>
<div id="Bus">
<div class="Row">
<div class="FreeSeat" ></div>
<div class="FreeSeat" ></div>
<div class="ResSeat" ></div>
<div class="ResSeat" ></div>
<div class="ResSeat" ></div>
</div>
</div>
<body>
</html>
It will be very helpful if anyone can help me out with this .
Considering that you want to use pure JS and not any library, you'd have to manually add event listeners to your classes.
And it has been solved for a similar problem here
var freeclass = document.getElementsByClassName("FreeSeat");
var myFunction_Free = function() {
this.style.color = "blue";
}
for(var i=0;i<freeclass.length;i++){
freeclass[i].addEventListener('click', myFunction_Free, false);
}
But for your case, here's a working fiddle
JQuery is amazing for these sorts of things.
Say you have a div with id 'box1'
<div id='box1'></div>
Style it with css
#box1 {
width:100px;
height:100px;
background-color:white;
border:1px solid black;
}
Using JQuery, you can make this call:
$( "#box1" ).click(function() {
$('#box1').css('background-color', 'red');
});
And now whenever your div is clicked, the colour will change, you can customise this however much you like.
Here is a JSFiddle demo.
Also, since you didn't specify exactly what you want to change the colour of, in my example jquery, it is telling the browser that when a div with an id of box1is clicked, change the background-color of the div with an id of box1, you can change anything though.
If you have a <p> tag you can change that too when the div is clicked, hope this helped!
You can use the following method to change the background color of an element by class:
const free_seat = document.getElementsByClassName('FreeSeat');
free_seat[0].style.backgroundColor = '#ff0';
Each element can be referenced by its index:
free_seat[0] // first div
free_seat[1] // second div
Therefore, we can create a function that will be called whenever the click event is delivered to the target:
const change_color = () => {
this.style.backgroundColor = '#ff0';
};
for (let i = 0; i < free_seat.length; i++) {
free_seat[i].addEventListener('click', change_color);
}
Note: You can also use document.querySelectorAll('.FreeSeat') to obtain a NodeList of elements of a certain class.
You can use simply the css focus pseudo-class for this:
#foo:focus {
background-color:red;
}
<div id="foo" tabindex="1">hello world!</div>
Dont forget to set the tabindex.

Target paragraphs containing only images

I have a div (blog post) containing multiple paragraphs.
Some of these contain text, other text + images and other only images.
I would like to target only the paragraphs containing only images and set text-align:center
Is this possible using only css or is js required?
Any suggestions?
Thanks
The following adds a special CSS class to all p tags that only contain img tags and whitespace:
$('.blog-post p').each(function(i){ // For each paragraph
if ( ($(this).find('img').length) && // If there's an image
(!$.trim($(this).text()).length)) // and there's no text
{
$(this).addClass('imgOnly'); // Add a special CSS class
}
});
The trim() function is used with text() to determine if the text only contains whitespace.
Sample content:
<div class="blog-post">
<p>Text</p>
<p><span>Text</span></p>
<p><img/></p> <!-- CSS class will be added -->
<p>Text <img/></p>
<p><span>Text</span><img/></p>
<p><img/> Text <img/></p>
<p><img/><img/></p> <!-- CSS class will be added -->
<p><img/> <img/></p> <!-- CSS class will be added -->
</div>
This example will help you: demo on jsFiddle
jQuery code:
$(function() {
var divs = $('.blog-post > div');
$.each(divs, function(i, div) {
/* cache variable */
var $div = $(div);
if ( !($div.find('p')[0]) ) { /* if there are no one p tag inside div */
$div.addClass('only-images');
}
});
});
CSS:
.blog-post > .only-images {
background-color: red; /* color is demo only */
}
So my example will add class only to third div containing only images in this example HTML markup:
<div class="blog-post">
<div>
<p>some text</p>
<p>some text</p>
<p>some text</p>
<p>some text</p>
</div>
<div>
<p>some text</p>
<img src="//placekitten.com/g/100/100" alt="" />
</div>
<div> <!-- only this div would be applied class `only-images` customizable by css -->
<img src="//placekitten.com/g/100/100" alt="" />
<img src="//placekitten.com/g/100/100" alt="" />
</div>
</div>​
To do this you can use javascript and write a function for it, you'll be best of using the javascript library Jquery. When you have a function for it you can later add new paragraphs and images without the need to write more code.
I would have written an example but I don't have much time. I hope I helped you a little
Css is not enough. You may use Css rules based on parents, but not based on children. For example you may target all images that appear inside paragraphs. The properties will apply to the images, and not to the paragraph. Example:
p img
{
/* properties */
}
Options remain Javascript or server-side, for example you could assign a specific class name to the paragraph based on the content (.imageOnly or .mixedContent).
I had to do this without jQuery and I came up with the following:
document.querySelectorAll('p').forEach(function(p) {
// if there's no image, stop
if (p.querySelector('img') === null) {
return;
}
// if there's text, stop
if (p.innerText.trim() !== "") {
return;
}
// otherwise, mark the paragraph
p.classList.add('img-only');
});
Only tested on modern browsers.

Categories