Get a part of attribute value from array - javascript

So basically i'm just trying to simplify this:
$('iframe[src*="foo"],iframe[src*="bar"]');
to something like:
var sources = ['foo', 'bar','something'];
$('iframe[src*="some string in array"]');
Hope you get the idea :)

You can insert the variable into the selector, like this:
var sources = ['foo', 'bar','something'];
$('iframe[src*="' + sources[0] + '"]');
See below for an example with images. The ones with red borders are selected as part of the array
var arr = ["http://placebear", "http://lorempixel", "http://placehold", "http://loremflickr"];
for(var i = 0; i < arr.length; i++) {
var $img = $('img[src*="'+arr[i]+'"]');
$img.addClass('inarray');
console.log($img);
}
img {
border: 3px solid #000;
border-radius: 50%;
}
img.inarray {
border-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img src="http://placebear.com/200/200" />
<img src="http://placecage.com/200/200" />
<img src="http://lorempixel.com/200/200" />
<img src="http://placehold.it/200x200" />
<img src="http://www.fillmurray.com/200/200" />
<img src="http://loremflickr.com/200/200" />

var sources = ['foo', 'bar','something'];
$('iframe[src*="'+sources[Math.floor(Math.random()*sources.length)]+'"]');

Related

I am trying to have a second slider on the same page but its not working

I am trying to have a second slider on the same page but its not working.
The first one works fine but the second one is not working. I think there is something wrong with the parent element method but cant wrap my head around it.
var ids = ["view_0", "view_1", "view_2", "view_3"]
let current_id = 0;
function next(productnr) {
if (document.getElementById(ids[current_id]).parentElement.id == productnr) {
let last_array_position = ids.length;
document.getElementById(ids[current_id]).classList.remove("show");
current_id++;
if (current_id >= last_array_position) {
current_id = 0;
}
document.getElementById(ids[current_id]).classList.add("show");
}
}
#1 img {
display: none;
}
#1 img.show {
display: block;
}
<article id=1>
<img class="show" id="view_0"></img>
<img id="view_1"></img>
<img id="view_2"></img>
<img id="view_3"></img>
<button><</button>
<button onclick="next(1)">></button>
<article id=2>
<img class="show" id="view_0"></img>
<img id="view_1"></img>
<img id="view_2"></img>
<img id="view_3"></img>
<button><</button>
<button onclick="next(2)">></button>
The reason your code doesn't work is that you are making use of the same id for both sliders in HTML. This will always update the former but never change the latter slide by your JavaScript function. Also, your code has a few issues like the tags aren't closed properly, no src attributes. Looks like you need multiple arrays for storing ids of multiple sliders, and multiple functions to handle previous and next buttons.
Here's a common function to handle all buttons of multiple sliders on a single page without any arrays:
function next(productId, next) {
var tags = document.getElementById(productId).getElementsByTagName("img");
var index;
for (let i = 0; i < tags.length; i++) {
if (tags[i].className == "show") {
index = i;
break;
}
}
tags[index].classList.remove("show")
index = next ? (index + 1) : (index - 1);
index = index == tags.length ? 0 : index == -1 ? tags.length - 1 : index;
tags[index].classList.add("show")
}
img {
display: none;
width: 100px;
height: 100px;
object-fit: cover;
}
img.show {
display: block;
}
<div id="product1">
<img class="show" src="https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885__480.jpg" />
<img src="https://images.ctfassets.net/hrltx12pl8hq/61DiwECVps74bWazF88Cy9/2cc9411d050b8ca50530cf97b3e51c96/Image_Cover.jpg?fit=fill&w=480&h=270" />
<img src="https://images.unsplash.com/photo-1453728013993-6d66e9c9123a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8Mnx8dmlld3xlbnwwfHwwfHw%3D&w=1000&q=80" />
<img src="https://www.gettyimages.com/gi-resources/images/500px/983794168.jpg" />
<button onclick="next('product1', 0)">Prev</button>
<button onclick="next('product1', 1)">Next</button>
</div>
<div id="product2">
<img class="show" src="https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885__480.jpg" />
<img src="https://images.ctfassets.net/hrltx12pl8hq/61DiwECVps74bWazF88Cy9/2cc9411d050b8ca50530cf97b3e51c96/Image_Cover.jpg?fit=fill&w=480&h=270" />
<img src="https://images.unsplash.com/photo-1453728013993-6d66e9c9123a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8Mnx8dmlld3xlbnwwfHwwfHw%3D&w=1000&q=80" />
<img src="https://www.gettyimages.com/gi-resources/images/500px/983794168.jpg" />
<button onclick="next('product2', 0)">Prev</button>
<button onclick="next('product2', 1)">Next</button>
</div>
The id attribute defines an identifier (ID) which must be unique in the whole document,
In your code you are using the same ID for multiple elements,
For what you are trying to do, I would suggest to use querySelector to select the elements as this will enable us to select exactly the component with the given id under the given slider since there are multiple elements with same id (In such repetitive case, the suggested way is using class instead of id).
I am taking a counter_id as counter of image for each slider having the id as the key of the slider.
Here, I updated the slider id as a1 and a2 for better understanding.
#${productnr}>.show#${ids[current_id[productnr]]} => select the element with class .show and id #view_0 (or so on as per counter_id of the slider) under the the element with id a1 (or a2) i.e. slider element.
We perform add and remove class operation on the element.
var ids = ["view_0", "view_1", "view_2", "view_3"]
let current_id = {
a1: 0,
a2: 0
}; //image counter for each slider having the id as the key of slider
function next(productnr) {
let last_array_position = ids.length;
let pic = document.querySelector(`#${productnr}>.show#${ids[current_id[productnr]]}`);
pic.classList.remove("show");
current_id[productnr]++;
if (current_id[productnr] >= last_array_position) {
current_id[productnr] = 0;
}
document.querySelector(`#${productnr}>#${ids[current_id[productnr]]}`).classList.add("show");
}
function prev(productnr) {
let last_array_position = ids.length;
let pic = document.querySelector(`#${productnr}>.show#${ids[current_id[productnr]]}`);
pic.classList.remove("show");
current_id[productnr]--;
if (current_id[productnr] < 0) {
current_id[productnr] = last_array_position - 1;
}
document.querySelector(`#${productnr}>#${ids[current_id[productnr]]}`).classList.add("show");
}
#a1 img {
display: none;
}
#a1 img.show {
display: block;
}
<article id="a1">
<img src="https://picsum.photos/id/1/200" class="show" id="view_0"></img>
<img src="https://picsum.photos/id/2/200" id="view_1"></img>
<img src="https://picsum.photos/id/3/200" id="view_2"></img>
<img src="https://picsum.photos/id/4/200" id="view_3"></img>
<button onclick="prev(`a1`)"><</button>
<button onclick="next(`a1`)">></button>
<article id="a2">
<img src="https://picsum.photos/id/50/200" class="show" id="view_0"></img>
<img src="https://picsum.photos/id/60/200" id="view_1"></img>
<img src="https://picsum.photos/id/70/200" id="view_2"></img>
<img src="https://picsum.photos/id/80/200" id="view_3"></img>
<button onclick="prev(`a2`)"><</button>
<button onclick="next(`a2`)">></button>
</article>
</article>

How can i select multiple pictures using change event?

How can i select multiple pictures. right now i'm able to get pictures single-single but i want to get multiple. how can i do that?
What i tried:-
$(function() {
$(document).on('change', '.caFileBtn', function() {
console.log(imagePath);
var files = this.files
for (var i = 0; i < files.length; i++) {
var file = files[i];
var imagePath = URL.createObjectURL(file);
}
var imageElement = `
<div>
<img src="${imagePath}" />
</div>
`;
$('.ca-photos-area').show();
$('.ca-photos-area').prepend(imageElement);
$(this).val('');
});
});
.ca-photos-area {
display: flex;
}
.ca-photos-area img {
width: 90px;
height: 90px;
margin: 5px;
border: 1px solid #ccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<div class="btn btn-primary btn-block">
<input type="file" Multiple="Multiple" class="caFileBtn" />
<i class="fas fa-image"></i>
</div>
<div class="col-md-12">
<div class="ca-photos-area mt-3">
</div>
</div>
Answer will be appreciated
While html tags and attributes are case-insensitive it's best practice to use lowercase. Though, attribute values are case-sensitive. So, you must define multiple in lowercase:
<input type="file" multiple="multiple" class="caFileBtn" />
<!-- Must be in lowercase --- ^^ -->
<!-- Otherwise, it's still single type -->
Or, you could also have defined attribute only:
<input type="file" multiple class="caFileBtn" />
The above answer seems to be wrong in the case of multiple attribute as it accepts boolean and using it case-insensitive also meant to be multiple.
Here's the working javascript code that will select all selected images:
$(function() {
$(document).on('change', '.caFileBtn', function() {
console.log(imagePath);
var files = this.files
var imageElement = [];
for (var i = 0; i < files.length; i++) {
var file = files[i];
var imagePath = URL.createObjectURL(file);
imageElement.push( `
<div>
<img src="${imagePath}" />
</div>`);
}
for (var i=0; i<imageElement.length; i++){
$('.ca-photos-area').prepend(imageElement[i]);
}
$('.ca-photos-area').show();
$(this).val('');
});
});
Issue
The majority of the statements within handler were outside the for loop. BTW I removed the reset statement: $(this).val('') because the tag would always display: "no files selected..." whether there were files selected or not. Without the reset you get a list of the file names selected.
Demo
$('.caFileBtn').on('change', function() {
const self = $(this)[0];
const files = self.files;
let imagePath, imageTag;
for (let i = 0; i < files.length; i++) {
let file = files[i];
imagePath = URL.createObjectURL(file);
imageTag = `<figure><img src="${imagePath}"></figure>`;
$('.ca-photos-area').prepend(imageTag);
}
});
.ca-photos-area {
display: flex;
}
.ca-photos-area img {
width: 90px;
height: 90px;
margin: 5px;
border: 1px solid #ccc;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
<link href="https://use.fontawesome.com/releases/v5.13.0/css/all.css" rel="stylesheet" crossorigin="anonymous">
<label class="btn btn-primary btn-block">
<input class="caFileBtn" type="file" multiple="multiple">
<i class="fas fa-image"></i>
</label>
<section class="col-md-12">
<article class="ca-photos-area mt-3"></article>
</section>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js'></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/js/bootstrap.min.js"></script>

Image Gallery: how to remove and add class when clicking an image

Beginner here.
I have a small image gallery, with two classes declared in CSS:
imagem: selected image, with border
imagem-activa: all the others, without border
How can i use JavaScript to add/remove the classes when the user clicks one image? I already know how to do it in jQuery, but want to learn also pure JS.
HTML
<div class="exercicio">
<h2 class="titulo">
Exercício 4
</h2>
<img src="img/imagem1.jpg" class="imagem imagem-activa" />
<img src="img/imagem2.jpg" class="imagem" />
<img src="img/imagem3.jpg" class="imagem" />
<img src="img/imagem4.jpg" class="imagem" />
</div>
CSS
.imagem{border:5px solid #000;opacity:0.5;cursor: pointer;}
.imagem-activa{border:5px solid #ff0066;opacity:1;}
JS
This part i can't make it work. Can someone help me?
var imagens = document.getElementsByClassName("imagem");
var imagemActual = 0;
for(var i = 0; i < imagens.length; i++) {
imagens[i].addEventListener("click", function() {
imagens[imagemActual].classList.remove("imagem-activa");
this.classList.add("imagem-activa");
imagemActual = i;
});
}
This is my working jQuery solution
$(".imagem").click(function() {
$(".imagem").removeClass("imagem-activa");
$(this).addClass("imagem-activa");
});
So, what is happening here is that anytime any of your click handlers is invoked, your variable imageActual gets set to the current value of i which will always be 4 because this is the final value of i after the for loop. For the first click, you might not run into any errors and you might get the expected result. But as soon as any of your event listeners has run, the value of imagemActual will be 4 and that will cause an error on any future invocation of your event listeners because imagens[4] will be undefined.
There are a few ways to solve this.
1) bind
You can bind the (temporary) value of i inside the loop to the event listener function:
var imagens = document.getElementsByClassName("imagem");
var imagemActual = 0;
for(var i = 0; i < imagens.length; i++) {
imagens[i].addEventListener("click", function(index) {
imagens[imagemActual].classList.remove("imagem-activa");
this.classList.add("imagem-activa");
imagemActual = index;
}.bind(imagens[i], i));
}
.imagem {
width: 20px;
height: 20px;
background-color: blue;
}
.imagem.imagem-activa {
background-color: red;
}
<div class="exercicio">
<h2 class="titulo">
Exercício 4
</h2>
<img src="" class="imagem imagem-activa" />
<img src="" class="imagem" />
<img src="" class="imagem" />
<img src="" class="imagem" />
</div>
2) let
If you can use ES6, you can use let which will make sure that your counting variable is a unique instance for every value that is applied:
const imagens = document.getElementsByClassName("imagem");
let imagemActual = 0;
for(let i = 0; i < imagens.length; i++) {
imagens[i].addEventListener("click", function() {
imagens[imagemActual].classList.remove("imagem-activa");
this.classList.add("imagem-activa");
imagemActual = i;
});
}
.imagem {
width: 20px;
height: 20px;
background-color: blue;
}
.imagem.imagem-activa {
background-color: red;
}
<div class="exercicio">
<h2 class="titulo">
Exercício 4
</h2>
<img src="" class="imagem imagem-activa" />
<img src="" class="imagem" />
<img src="" class="imagem" />
<img src="" class="imagem" />
</div>

wrapping images in dynamically created divs in JS

I'm having difficulties to wrap my images with dynamically created divs in JS. This is the code which I used:
var images = document.getElementsByTagName("img");
for(var i = 0; i < images.length; i++) {
var wrapper = document.createElement("div");
wrapper.appendChild(images[i]);
mainpictureframe.appendChild(wrapper);
wrapper.style.background = "red";
}
* {
margin: 0;
padding: 0;
font-size: 15px;
}
img{
max-width:236px;
}
<main id="mainpictureframe">
<img src="http://cdn.wallpapersafari.com/61/30/us7TlD.jpg" alt="Stonehenge1" title="16by9-1"/>
<img src="http://cdn.wallpapersafari.com/61/30/us7TlD.jpg" alt="Stonehenge2" title="16by9-1"/>
<img src="http://cdn.wallpapersafari.com/61/30/us7TlD.jpg" alt="Stonehenge3" title="16by9-1"/>
<img src="http://cdn.wallpapersafari.com/61/30/us7TlD.jpg" alt="Stonehenge4" title="16by9-1"/>
<img src="http://cdn.wallpapersafari.com/61/30/us7TlD.jpg" alt="Stonehenge5" title="16by9-1"/>
<img src="http://www.freecomputerdesktopwallpaper.com/new_wallpaper/5_4_3_2_1_Happy_New_Year_freecomputerdesktopwallpaper_p.jpg" alt="otherexample1" title="4by3-1"/>
<img src="http://www.freecomputerdesktopwallpaper.com/new_wallpaper/5_4_3_2_1_Happy_New_Year_freecomputerdesktopwallpaper_p.jpg" alt="otherexample2" title="4by3-1"/>
<img src="http://www.freecomputerdesktopwallpaper.com/new_wallpaper/5_4_3_2_1_Happy_New_Year_freecomputerdesktopwallpaper_p.jpg" alt="otherexample3" title="4by3-1"/>
<img src="http://www.freecomputerdesktopwallpaper.com/new_wallpaper/5_4_3_2_1_Happy_New_Year_freecomputerdesktopwallpaper_p.jpg" alt="otherexample4" title="4by3-1"/>
<img src="http://www.freecomputerdesktopwallpaper.com/new_wallpaper/5_4_3_2_1_Happy_New_Year_freecomputerdesktopwallpaper_p.jpg" alt="otherexample5" title="4by3-1"/>
</main>
It seems like it correctly creates the divs, but only packs every second image into a div.
Thanks for the help
Explanation:
getElementsByTagName returns a live HTMLCollection. Live means that the HTMLCollection reflect the DOM. If some elements get removed, the HTMLCollection get shrunk accordingly.
Since you are looping from the begining of the loop, some elements get left behind.
If the HTMLCollection of images is:
[a, b, c, d].
then:
i = 0 and length = 4
a b c d
^
i
then a get removed from the collection and i get incremented, next:
i = 1 and length = 3
b c d
^
i
c get removed and b will be skipped because b is now at position 0 (because a was removed) and i is at 1 where c is.
.... and so on.
That explains why one image get wrapped and one not...
Fix:
Instead of a for loop, just make a while loop, that checks whether there is still images:
var images = document.getElementsByTagName("img");
var mainpictureframe = document.getElementById("mainpictureframe");
var len = images.length;
while (len--) {
var wrapper = document.createElement("div");
var image = mainpictureframe.removeChild(images[0]);
wrapper.appendChild(image);
mainpictureframe.appendChild(wrapper);
}
Working fiddle:
var images = document.getElementsByTagName("img");
var mainpictureframe = document.getElementById("mainpictureframe");
var len = images.length;
while (len--) {
var wrapper = document.createElement("div");
var image = mainpictureframe.removeChild(images[0]);
wrapper.appendChild(image);
mainpictureframe.appendChild(wrapper);
}
* {
margin: 0;
padding: 0;
font-size: 15px;
}
img {
max-width: 236px;
}
div {
padding: 5px;
border: 5px solid red;
}
<main id="mainpictureframe">
<img src="http://cdn.wallpapersafari.com/61/30/us7TlD.jpg" alt="Stonehenge1" title="16by9-1" />
<img src="http://cdn.wallpapersafari.com/61/30/us7TlD.jpg" alt="Stonehenge2" title="16by9-1" />
<img src="http://cdn.wallpapersafari.com/61/30/us7TlD.jpg" alt="Stonehenge3" title="16by9-1" />
<img src="http://cdn.wallpapersafari.com/61/30/us7TlD.jpg" alt="Stonehenge4" title="16by9-1" />
<img src="http://cdn.wallpapersafari.com/61/30/us7TlD.jpg" alt="Stonehenge5" title="16by9-1" />
<img src="http://www.freecomputerdesktopwallpaper.com/new_wallpaper/5_4_3_2_1_Happy_New_Year_freecomputerdesktopwallpaper_p.jpg" alt="otherexample1" title="4by3-1" />
<img src="http://www.freecomputerdesktopwallpaper.com/new_wallpaper/5_4_3_2_1_Happy_New_Year_freecomputerdesktopwallpaper_p.jpg" alt="otherexample2" title="4by3-1" />
<img src="http://www.freecomputerdesktopwallpaper.com/new_wallpaper/5_4_3_2_1_Happy_New_Year_freecomputerdesktopwallpaper_p.jpg" alt="otherexample3" title="4by3-1" />
<img src="http://www.freecomputerdesktopwallpaper.com/new_wallpaper/5_4_3_2_1_Happy_New_Year_freecomputerdesktopwallpaper_p.jpg" alt="otherexample4" title="4by3-1" />
<img src="http://www.freecomputerdesktopwallpaper.com/new_wallpaper/5_4_3_2_1_Happy_New_Year_freecomputerdesktopwallpaper_p.jpg" alt="otherexample5" title="4by3-1" />
</main>
var images = document.getElementsByTagName("img");
var wrapper = [];
for (var i = 0; i < images.length; i++){
mainpictureframe.appendChild('<div>'+images[i]+'</div>');
}
Then you just remove the original images i guess

Targeting one of multiple Classes / only part of the Class string - className vs classList

So I'm trying to put together a Javascript toggle for my photography portfolio site. My goal is to be able to click a button labeled Show Only Sunsets and hide every image without a "Sunsets" Class. The code I've come up with below ALMOST works, but there's a major flaw:
This code only preserves the visibility of images such as "1.jpg" below whose Class is exactly/only "Sunsets" (or "NSFW," or whatever). But often I'll need to give images more than one class, for example to differentiate verticals, or images that fall into multiple categories. So I need the code to preserve the visibility of any image such as "2.jpg" below which has "Sunsets" (or whatever) anywhere in its Class.
JS:
<script>
function filterOn(imageClass) {
var image = document.getElementsByTagName('figure');
for (i = 0; i < image.length; i++) {
if (image[i].className != imageClass) {
image[i].style.display = 'none';
}
}
document.getElementById(imageClass + '-off').innerHTML = 'Undo Filter';
document.getElementById(imageClass + '-off').setAttribute('onClick', "filterOff('" + imageClass + "')");
document.getElementById(imageClass + '-off').id = imageClass + '-on';
}
function filterOff(imageClass) {
var image = document.getElementsByTagName('figure');
for (i = 0; i < image.length; i++) {
if (image[i].className != imageClass) {
image[i].style.display = 'inline-block';
}
}
document.getElementById(imageClass + '-on').innerHTML = 'Show Only ' + imageClass;
document.getElementById(imageClass + '-on').setAttribute('onClick', "filterOn('" + imageClass + "')");
document.getElementById(imageClass + '-on').id = imageClass + '-off';
}
</script>
HTML:
<ul>
<li id="Sunsets-off" onClick="filterOn('Sunsets')">Show Only Sunsets</li>
<li id="NSFW-off" onClick="filterOn('NSFW')">Show Only NSFW</li>
</ul>
<img class="Sunsets" src="1.jpg">
<img class="vertical Sunsets" src="2.jpg">
<img class="NSFW vertical" src="3.jpg">
<img class="Architectural" src="4.jpg">
<img class="Sunsets Landscapes" src="5.jpg">
<img class="Abstract" src="6.jpg">
<img class="NSFW LondonAndrews" src="7.jpg">
That test:
if (image[i].className != imageClass) {
will indeed do a check against the whole class string.
There's the classList API for doing what you want, replacing your test with:
if (!image[i].classList.contains(imageClass)) {
I would simplify it by adding a class name to all images so you can easily target all the images, then use a toggled class to hide the images you don't want to see. this also gives you the ability to use css3 animations to fade the images you don't want to see.
function filterOn( clazz ){
// get all the images using the additional img class
var images = slice(document.getElementsByClassName('img'));
// hide all the images
var ret = images.map(function( image ){
image.classList.add('hide');
return image;
})
// reduce the images to only contain those you want to show
.filter(function( image ){
return image.classList.contains( clazz );
})
// show the image by removing the hide class
.forEach(function( image ){
image.classList.remove('hide');
});
}
// show all images
function showAll(){
var images = slice(document.getElementsByClassName('img'));
images.forEach(function( image ){
image.classList.remove('hide');
});
}
// helper function to get an array from an array like object
function slice( arrayLike ){
return Array.prototype.slice.call( arrayLike );
}
.img {
display: block;
float: left;
margin-left: .8em;
border: .3em solid #aaa;
}
.hide {
display: none;
}
.filters {
display: block;
width: 100%;
float: left;
}
.Sunsets {
border: .3em solid orange;
}
.NSFW {
border: .3em solid magenta;
}
<nav class="filters">
<button id="Sunsets-off" onClick="filterOn('Sunsets')">Show Only Sunsets</button>
<button id="NSFW-off" onClick="filterOn('NSFW')">Show Only NSFW</button>
<button id="show-all" onClick="showAll()">Show All</button>
</nav>
<!-- I added an img class to the images for ease of use later -->
<section class="images">
<img class="img Sunsets" src="http://placehold.it/50/50">
<img class="img vertical Sunsets" src="http://placehold.it/50/50">
<img class="img NSFW vertical" src="http://placehold.it/50/50">
<img class="img Architectural" src="http://placehold.it/50/50">
<img class="img Sunsets Landscapes" src="http://placehold.it/50/50">
<img class="img Abstract" src="http://placehold.it/50/50">
<img class="img NSFW LondonAndrews" src="http://placehold.it/50/50">
</section>

Categories