Get elements that don't contain a figure using plain javascript - javascript

I am trying to get all parent items that don't contain a figure. Then I will loop through that and wrap the images inside it in a figure if that figure does not already exist. I have successfully looped through and wrapped each image in a figure however if the figure already exists I want to do skip it. I am hoping to use only javascript and not jquery. Thanks for any help
HTML
<div class="carousel-item active">
<figure class="figure-image">
<img src="https://via.placeholder.com/350x150" class="Image-1" alt="Second Slider Slide">
</figure>
</div>
<div class="carousel-item">
<img src="https://via.placeholder.com/350x150" class="Image-2" alt="Second Slider Slide">
</div>
JS
This JS loops through and wraps all images in a figure but if a figure already exists as per my example above if will add a figure and way resulting in one element having two figures. I think the solution will be to just grab the carosuelItems without .figure-images inside right form the start but I am unsure how to do this.
let carouselItem = [...document.querySelectorAll('.slider-image .carousel-item')]
for (let i = 0; i < carouselItem.length; i++) {
// Check to see if a figurea lready exists
// Create a figure for each class and add class to it.
let figure = document.createElement('figure')
figure.classList.add('figure-image')
// Get all images inside of the slider
let carouselImg = [...carouselItem[i].querySelectorAll('img')]
for (let img of carouselImg) {
// Insert the images into each figure
figure.insertAdjacentElement('afterbegin', img)
}
// Finally insert the figure with the image into each carousel slot
carouselItem[i].insertAdjacentElement('afterbegin', figure)
}

You can check if the element has a child element <figure> using something like this: carouselItem[i].querySelector("figure")
Here is a complete example:
let carouselItem = [...document.querySelectorAll('.carousel-item')]
for (let i = 0; i < carouselItem.length; i++) {
if(!carouselItem[i].querySelector("figure")){
// Check to see if a figurea lready exists
// Create a figure for each class and add class to it.
let figure = document.createElement('figure')
figure.classList.add('figure-image')
// Get all images inside of the slider
let carouselImg = [...carouselItem[i].querySelectorAll('img')]
for (let img of carouselImg) {
// Insert the images into each figure
figure.insertAdjacentElement('afterbegin', img)
}
// Finally insert the figure with the image into each carousel slot
carouselItem[i].insertAdjacentElement('afterbegin', figure)
}
}
<div class="carousel-item active">
<figure class="figure-image">
<img class="Image-1" src="https://via.placeholder.com/350x150" alt="Second Slider Slide">
</figure>
</div>
<div class="carousel-item">
<img class="Image-2" src="https://via.placeholder.com/350x150" alt="Second Slider Slide">
</div>

This is from MDN Web Docs:
"Since the document fragment is in memory and not part of the main DOM tree, appending children to it does not cause page reflow (computation of element's position and geometry). Historically, using document fragments could result in better performance."
In my code I'm using the createDocumentFragment() method.
let imgs = Array.from(document.querySelectorAll("img"));
for(let i = 0; i < imgs.length; i++){
let img = imgs[i]
let parentdiv = img.parentNode;
if(parentdiv.tagName.toLowerCase() == "figure"){
continue;
}else{
let fragment = document.createDocumentFragment();
let figureParent = document.createElement("figure");
figureParent.setAttribute("class","figure-image");
figureParent.appendChild(img)
fragment.appendChild(figureParent);
parentdiv.appendChild(fragment)
}
}
figure{border:1px solid}
<div class="carousel-item active">
<figure class="figure-image">
<img class="Image-1" src="https://rpc.virtualhighschool.com/v3_demo/department/demo/course/ver-a/style_template_30/parts-of-a-cell.jpg" alt="Second Slider Slide">
</figure>
</div>
<div class="carousel-item">
<img class="Image-2" src="https://rpc.virtualhighschool.com/v3_demo/department/demo/course/ver-a/style_template_30/parts-of-a-cell.jpg" alt="Second Slider Slide">
</div>

Related

Carousel - linking to slide from another page - why JS not working?

I'm trying to following this but it's 6 years old. Have things change 'cause my js doesn't seem to get triggered when the URL contains #slide_ ?
Linking to a certain bootstrap carousel slide from another page
My code on page2:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>test</title>
<!-- Core theme CSS (includes Bootstrap)-->
<link href="css/styles.css?v20221223=1" rel="stylesheet" />
</head>
<body>
<!-- Carousel Wrapper-->
<div id="myCarousel" class="carousel carousel-dark slide" data-bs-interval="false" data-ride="carousel" data-pause="hover">
<div class="carousel-inner">
<div class="carousel-item active">
<img src="https://www.w3schools.com/bootstrap/chicago.jpg" alt="..." class="d-block img-fluid">
</div>
<div class="carousel-item">
<img src="https://www.w3schools.com/bootstrap/la.jpg" alt="..." class="d-block img-fluid">
</div>
<div class="carousel-item">
<img src="https://www.w3schools.com/bootstrap/ny.jpg" alt="..." class="d-block img-fluid">
</div>
</div>
</div>
</div>
<!-- END Carousel Wrapper-->
<!-- Bootstrap core JS - versionas as of Dec 2022-->
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
<!-- JS for loading a particular slide from another page -->
<script>
function qs(key) {
key = key.replace(/[*+?^$.\[\]{}()|\\\/]/g, "\\$&");
var match = location.search.match(new RegExp("[?&]" + key + "=([^&]+)(&|$)"));
var slide = match && decodeURIComponent(match[1].replace(/\+/g, " "));
if (Math.floor(slide) == slide && $.isNumeric(slide))
return parseInt(slide);
else
return 0;
}
//why this isn't working???
$('#myCarousel').carousel(qs('slide'));
</script>
</body>
</html>
And the link on page 1
slide 2
I'm stuck...
In your example you added your JS in page 2, but your link redirects the user to page 1. Make sure you get your URLs correct, so based on your example it should be slide 2 on page 1.
Furthermore, the function function qs(key) {..} extracts the hash on ? not on #.
Don't worry though, what you want is simple, so I wrote a quick example for you.
Explaining the snippet below
You can achieve your desired functionality without needing jQuery.
In my example I created a function called getSlideNumber(). This first checks if the location hash exists, then we get it's value and split it on the = to get to the slide number. After that, we convert value into an integer using parseInt(). If that fails, the parseInt() function returns NaN so we also make sure our slide number is in fact an integer before we return it using Number.isInteger(). This way we protect ourselves against any malicious hashes.
We then call that function to get our slide number and use Bootstrap's method getOrCreateInstance to get the carousal instance that's on our page and make it cycle to the slide number using to().
And that's all it is!
Usage
We can't extract a hash in a snippet, so I don't call the function getSlideNumber() in my example. Therefore, make sure you delete the line const slideNumber = 2 and remove the // in front of the line above it when you want to use this code for your own project. Like so:
const slideNumber = getSlideNumber();
const element = document.querySelector('#carouselExample')
const caroursal = bootstrap.Carousel.getOrCreateInstance(element).to(slideNumber);
Also, note that the first slide of a carousal has an index of 0, similar to an array.
Lastly, you can edit the carousal HTML as you please, I used the basic example from the documentation.
The snippet
window.onload = function(){
function getSlideNumber() {
if(location.hash && location.hash.length) {
const value = location.hash.substr(1).split('=')[1];
const int = parseInt(value);
if (Number.isInteger(int)) {
return int;
} else {
return 0;
}
}
return 0;
}
//const slideNumber = getSlideNumber();
const slideNumber = 2; // Uncomment the line above and remove this line, it's only for demonstration purposes.
const element = document.querySelector('#carouselExample')
const caroursal = bootstrap.Carousel.getOrCreateInstance(element).to(slideNumber);
};
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.3.0-alpha1/dist/js/bootstrap.bundle.min.js" integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC+nuZB+EYdgRZgiwxhTBTkF7CXvN" crossorigin="anonymous"></script>
<div class="container">
<div id="carouselExample" class="carousel slide">
<div class="carousel-inner">
<div class="carousel-item active">
<img src="https://www.w3schools.com/bootstrap/chicago.jpg" class="d-block w-100" alt="...">
</div>
<div class="carousel-item">
<img src="https://www.w3schools.com/bootstrap/la.jpg" class="d-block w-100" alt="...">
</div>
<div class="carousel-item">
<img src="https://www.w3schools.com/bootstrap/ny.jpg" class="d-block w-100" alt="...">
</div>
</div>
<button class="carousel-control-prev" type="button" data-bs-target="#carouselExample" data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="visually-hidden">Previous</span>
</button>
<button class="carousel-control-next" type="button" data-bs-target="#carouselExample" data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="visually-hidden">Next</span>
</button>
</div>
</div>
Solution with jQuery
But wait! What if you can't live without jQuery? Worry no more, use this instead:
$(document).ready(function() {
function getSlideNumber() {
if(location.hash && location.hash.length) {
const value = location.hash.substr(1).split('=')[1];
const int = parseInt(value);
if (Number.isInteger(int)) {
return int;
} else {
return 0;
}
}
return 0;
}
const slideNumber = getSlideNumber();
$("#carouselExample").carousel(slideNumber);
});
Multiple carousals on one page
Assuming all carousals should be set to slideNumber we can target all carousals on the page with the class .carousal and then loop through them, like so:
const slideNumber = getSlideNumber();
const carousels = document.querySelectorAll('.carousel');
carousels.forEach(carousel => {
bootstrap.Carousel.getOrCreateInstance(carousel).to(slideNumber);
});
This works fine, but all carousals will cycle to the same slideNumber. If say your hash contains multiple values like page2.html#slide=2&slide=3 and you want the second carousal to cycle to slide 3 you would have to make getSlideNumber() return an object with all the slide numbers, then get the id of carousal inside the forEach loop and apply the corresponding slide number you have in the previous mentioned object in the to() method on the carousal id. That would be just one possible way of doing it.
Hope that helps. Good luck!

Resize images in div if the div has no text but only one or two images

I am trying to build a chat application, so i came across this little problem:
This is a div element with text and an image which will be styled normally
<div class="msg">
lets try that again shall we <img class="emojione" alt="😆" title=":laughing:" src="https://cdn.jsdelivr.net/emojione/assets/4.5/png/32/1f606.png">
</div>
This is a div element with an image and no text, since there is only one image i want to style the size of that image
<div class="msg">
<img class="emojione" alt="😆" title=":laughing:" src="https://cdn.jsdelivr.net/emojione/assets/4.5/png/32/1f606.png">
</div>
just like this
My first question on stack overflow, be nice thanks!
I have added the code, which picks up all the nodes in the DOM with the class name msg checks for the condition (the one you specified in the question) and modifies the only img messages.
const arr = document.getElementsByClassName('msg');
for (let i = 0; i < arr.length; i++) {
if (arr[i].innerText.length === 0 && arr[i].children.length == 1 && arr[i].children[0].classList.contains('emojione')) {
arr[i].children[0].classList.add('big-img');
}
}
.big-img{
transform: scale(1.5)
}
<div class="msg">
lets try that again shall we <img class="emojione" alt="😆" title=":laughing:"
src="https://cdn.jsdelivr.net/emojione/assets/4.5/png/32/1f606.png">
</div>
<div class="msg">
<img class="emojione" alt="😆" title=":laughing:"
src="https://cdn.jsdelivr.net/emojione/assets/4.5/png/32/1f606.png">
</div>

Randomizing 4 div elements in a row Javascript + JQuery

I have 4 div elements in a row (they are cards). I need to mix these divs on every page reflesh. How can I mix them?
I did this:
var random = Math.floor(Math.random() * $(".card").length);
$(".card")
.hide()
.eq(random)
.show();
But it gives just 1 random div. I need 4 random divs.
Here is the divs:
<div className="card clubs" ref="card1">
<img className="img" src={a} alt="a" />
</div>
<div className="card diamonds" ref="card2">
<img className="img" src={b} alt="b" />
</div>
<div className="card hearts" ref="card3">
<img className="img" src={c} alt="c" />
</div>
<div className="card spades" ref="card4">
<img className="img" src={d} alt="d" />
</div>
You can use something like this:
var parent = $("#cards"); // Parent container containing '.card' objects
var cards = parent.children();
while (cards.length) {
parent.append(cards.splice(Math.floor(Math.random() * cards.length), 1)[0]);
}
assuming your cards are wrapped in:
<div id='cards'>
<div className="card clubs" ref="card1">
<img className="img" src={a} alt="a" />
</div>
<div className="card diamonds" ref="card2">
<img className="img" src={b} alt="b" />
</div>
<div className="card hearts" ref="card3">
<img className="img" src={c} alt="c" />
</div>
<div className="card spades" ref="card4">
<img className="img" src={d} alt="d" />
</div>
</div>
What your code does, is choosing the card that will be displayed ("randomly"). If you want to display all the four cards and just shuffle their position, you will have to reposition them randomly.
https://css-tricks.com/snippets/jquery/shuffle-children/
$.fn.shuffleChildren = function() {
$.each(this.get(), function(index, el) {
var $el = $(el);
var $find = $el.children();
$find.sort(function() {
return 0.5 - Math.random();
});
$el.empty();
$find.appendTo($el);
});
};
randojs.com can handle jQuery elements, so it makes this kinda simple.
//grab shuffled array of jQuery card elements
var shuffledCards = randoSequence($(".card"));
//store their shuffled htmls
var shuffledCardHTMLs = [];
for(var i = 0; i < shuffledCards.length; i++){
shuffledCardHTMLs[i] = shuffledCards[i].value[0].outerHTML;
}
//replace cards on page with those shuffled htmls
for(var i = 0; i < shuffledCardHTMLs.length; i++){
$(".card").eq(i)[0].outerHTML = shuffledCardHTMLs[i];
}
This solution does NOT care where on the page the card elements are located; it will handle anything. We store the htmls before we start replacing card elements on the page because we don't want to end up trying to access the html of an element that we've already overwritten. If you want to use this code, just toss this in the head tag of your HTML document first:
<script src="https://randojs.com/1.0.0.js"></script>

JS Dom manipulation issue

So i am creating a carousel generator framework and I want to make the implementation as simple as possible for the user. The developer is supposed to add
images without caring about design/responsiveness. The framework must take every image and insert it in a div with the classname of "slide". In this case from this code:
<div id="album" class="album">
<img src="./assets/img1.jpeg" alt="img1">
<img src="./assets/img2.jpeg" alt="img2">
<img src="./assets/img3.jpeg" alt="img3">
<img src="./assets/img4.jpeg" alt="img4">
<img src="./assets/img5.jpeg" alt="img5">
<img src="./assets/img6.jpeg" alt="img6">
</div>
the framework should generate this:
<div class="slide">
<img src="./assets/img1.jpeg" alt="img1">
</div>
<div class="slide">
<img src="./assets/img2.jpeg" alt="img2">
</div>
<div class="slide">
<img src="./assets/img3.jpeg" alt="img3">
</div>
<div class="slide">
<img src="./assets/img4.jpeg" alt="img4">
</div>
<div class="slide">
<img src="./assets/img5.jpeg" alt="img5">
</div>
<div class="slide">
<img src="./assets/img6.jpeg" alt="img6">
</div>
But the following code generates only 3 of the 6 images:
let album = document.getElementById("album");
let nextButton = document.getElementById('nextButton');
nextButton.addEventListener('', () => {
album.scrollBy(window.innerWidth, 0);
})
Object.keys(album.children).forEach(key => {
if (album.children[key].tagName === 'IMG') {
let newDiv = document.createElement('div');
newDiv.className = "slide";
newDiv.append(album.children[key]);
album.replaceChild(newDiv, album.children[key]);
}
})
and has an error:
Uncaught TypeError: Cannot read property 'tagName' of undefined
at Object.keys.forEach.key (index.js:9)
at Array.forEach (<anonymous>)
at index.js:8
and the generated carousel is:
Ideas? Thanks in advance.
This happens because .children creates a live collection of nodes so the iteration changes while you insert new children div inside the forEach
you could instead create a static collection like
let nodes = document.querySelectorAll('#album > img');
and iterate over that collection of nodes
let album = document.getElementById('album');
let nodes = document.querySelectorAll('#album > img');
Object.keys(nodes).forEach(i => {
let slide = document.createElement('div');
slide.className = 'slide';
slide.appendChild(nodes[i]);
album.appendChild(slide)
});
Codepen demo
The generated source is

How to target all classes with javascript. No jQuery

I am writing a responsive program that keeps changing the width of sertain elements, corresponding to other elements which have a % based width. Which works fine. But i ran into a problem when i wanted to change all images in side a div to be as big as the grand parent of the images.
JS:
var thebigone = document.getElementById('imgpresentation');
var demimages = document.getElementsByClassName('presentatinthis');
fixtheresponsiveness = setInterval(fixthis,1000);
function fixthis()
{
demimages.style.width = thebigone.offsetWidth+"px";
}
fixtheresponsiveness();
HTML:
<div id="imgpresentation" class="imgpresentation">
<div id="slidethemimgpresentation" class="slidethemimgpresentation">
<img class="presentatinthis" src="img/billeder/xyachtvisit/xyachtbesoeg1.jpg"/>
<img class="presentatinthis" src="img/billeder/xyachtvisit/xyachtbesoeg2.jpg"/>
<img class="presentatinthis" src="img/billeder/xyachtvisit/xyachtbesoeg3.jpg"/>
<img class="presentatinthis" src="img/billeder/xyachtvisit/xyachtbesoeg4.jpg"/>
<img class="presentatinthis" src="img/billeder/xyachtvisit/xyachtbesoeg5.jpg"/>
<img class="presentatinthis" src="img/billeder/xyachtvisit/xyachtbesoeg6.jpg"/>
<img class="presentatinthis" src="img/billeder/xyachtvisit/xyachtbesoeg7.jpg"/>
<img class="presentatinthis" src="img/billeder/xyachtvisit/xyachtbesoeg8.jpg"/>
<img class="presentatinthis" src="img/billeder/xyachtvisit/xyachtbesoeg9.jpg"/>
<img class="presentatinthis" src="img/billeder/xyachtvisit/xyachtbesoeg10.jpg"/>
</div>
</div>
It works if i replace "class" with "id" and "getelementsbyclassname" with "getelementbyid" but then it only works on the first img inside the div.
I do not wish to use jQuery, so please do not suggest $('.presentatinthis')
document.getElementsByClassName returns a NodeList, which means you would have to loop over the result to access and set each Node's style
var i = demimages.length;
while (i--) demimages[i].style.width = thebigone.offsetWidth+"px";

Categories