please help me simplify: show/hide thumbnails and large images - javascript

So I'm very beginner with javascript and would love some help simplifying this code.
I have a series of thumbnails arranged in a specific pattern, and when you click on a thumbnail, I'd like all the thumbnails to disappear, and the corresponding larger image to become visible. Then, when you click on the large image, it disappears and all the thumbnails are visible again. Each thumbnail has its own div id because they all have their unique positions.
I've figured out a way to do it, but it's very repetitive.
HTML:
<style type="text/css">
#largeimage_wrapper {visibility: hidden;}
</style>
</head>
<body>
<div id="thumbnail_wrapper">
<div id="thumbnail1"><img src="thumbnail1.jpg" onClick="get_big1();"/></div>
<div id="thumbnail2"><img src="thumbnail2.jpg" onClick="get_big2();"/></div>
<div id="thumbnail3"><img src="thumbnail3.jpg" onClick="get_big3();"/></div>
...etc
</div>
<div id="largeimage_wrapper">
<div id="large1"><img src="thumbnail1.jpg" onClick="get_thumbs1();"/></div>
<div id="large2"><img src="thumbnail2.jpg" onClick="get_thumbs2();"/></div>
<div id="large3"><img src="thumbnail3.jpg" onClick="get_thumbs3();"/></div>
...etc
</div>
</body>
javascript:
get_big1() {
document.getElementById('thumbnailwrapper').style.visibility='hidden';
document.getElementById('large1').style.visibility='visible';
}
get_thumbs1() {
document.getElementById('thumbnailwrapper').style.visibility='visible';
document.getElementById('large1').style.visibility='hidden';
}
get_big2() {
document.getElementById('thumbnailwrapper').style.visibility='hidden';
document.getElementById('large2').style.visibility='visible';
}
get_thumbs2() {
document.getElementById('thumbnailwrapper').style.visibility='visible';
document.getElementById('large2').style.visibility='hidden';
}
get_big3() {
document.getElementById('thumbnailwrapper').style.visibility='hidden';
document.getElementById('large3').style.visibility='visible';
}
get_thumbs3() {
document.getElementById('thumbnailwrapper').style.visibility='visible';
document.getElementById('large3').style.visibility='hidden';
}
</script>
There must be a better way! I imagine it's not that difficult, I just can't to get a grasp on it yet. Thanks in advance.

There are lots of ways to tackle this. The first and most obvious that comes to my mind is simply to pass a number into a single function which determines the image id to modify:
function get_thumbs(id) {
document.getElementById('thumbnailwrapper').style.visibility='visible';
document.getElementById('large' + id).style.visibility='hidden';
}
<div id="largeimage_wrapper">
<div id="large1"><img src="thumbnail1.jpg" onClick="get_thumbs(1);"/></div>
<div id="large2"><img src="thumbnail2.jpg" onClick="get_thumbs(2);"/></div>
<div id="large3"><img src="thumbnail3.jpg" onClick="get_thumbs(3);"/></div>
...etc
</div>
... And the same thing for get_big().
Alternatively you can use just one function that handles both conditions (big or thumbnail):
function get_img(id, type) {
if (type == 'big') {
document.getElementById('thumbnailwrapper').style.visibility='hidden';
document.getElementById('large' + id).style.visibility='visible';
}
else if (type == 'thumb') {
document.getElementById('thumbnailwrapper').style.visibility='visible';
document.getElementById('large' + id).style.visibility='hidden';
}
else return false;
}
And in the HTML:
<div id="thumbnail_wrapper">
<div id="thumbnail1"><img src="thumbnail1.jpg" onClick="get_img(1, 'big');"/></div>
<div id="thumbnail2"><img src="thumbnail2.jpg" onClick="get_img(2, 'big');"/></div>
<div id="thumbnail3"><img src="thumbnail3.jpg" onClick="get_img(3, 'big);"/></div>
...etc
</div>
<div id="largeimage_wrapper">
<div id="large1"><img src="thumbnail1.jpg" onClick="get_img(1, 'thumb');"/></div>
<div id="large2"><img src="thumbnail2.jpg" onClick="get_img(2, 'thumb');"/></div>
<div id="large3"><img src="thumbnail3.jpg" onClick="get_img(3, 'thumb');"/></div>
...etc
</div>

You could simplify by making it all into two functions and using an input to drive which item is affected:
HTML:
<style type="text/css">
#largeimage_wrapper {visibility: hidden;}
</style>
</head>
<body>
<div id="thumbnail_wrapper">
<div id="thumbnail1"><img src="thumbnail1.jpg" onClick="get_big(1);"/></div>
<div id="thumbnail2"><img src="thumbnail2.jpg" onClick="get_big(2);"/></div>
<div id="thumbnail3"><img src="thumbnail3.jpg" onClick="get_big(3);"/></div>
...etc
</div>
<div id="largeimage_wrapper">
<div id="large1"><img src="thumbnail1.jpg" onClick="get_thumbs(1);"/></div>
<div id="large2"><img src="thumbnail2.jpg" onClick="get_thumbs(2);"/></div>
<div id="large3"><img src="thumbnail3.jpg" onClick="get_thumbs(3);"/></div>
...etc
</div>
</body>
javascript:
get_big(id) {
document.getElementById('thumbnailwrapper').style.visibility='hidden';
document.getElementById('large'+id).style.visibility='visible';
}
get_thumbs(id) {
document.getElementById('thumbnailwrapper').style.visibility='visible';
document.getElementById('large'+id).style.visibility='hidden';
}

A library like jQuery can make this far easier, but here is how you can improve your code using javascript.
First, modify your html to include classes. We will then use these to gather the selected items. Also remove the inline onclick handlers. Try not to mix js and html.
<div id="thumbnail_wrapper">
<div class="thumbnail" id="thumbnail1"><img src="thumbnail1.jpg" /></div>
<div class="thumbnail" id="thumbnail2"><img src="thumbnail2.jpg" /></div>
<div class="thumbnail" id="thumbnail3"><img src="thumbnail3.jpg" /></div>
</div>
<div id="largeimage_wrapper">
<div class="large" id="large1"><img src="thumbnail1.jpg" /></div>
<div class="large" id="large2"><img src="thumbnail2.jpg" /></div>
<div class="large" id="large3"><img src="thumbnail3.jpg" /></div>
</div>
Next it is useful to use CSS to change the visibility of elements instead of directly modifying the style attribute. This makes style changes down the road far easier.
div#thumbnail_wrapper .hidden { visibility: hidden; }
div.large .hidden { visibility: hidden; }
Next we can use getElementsByClassName to attach onclick handlers
var thumbs = document.getElementsByClassName('thumbnail');
var large = document.getElementsByClassName('large');
for (var i = 0; i < thumbs.length; i++) {
thumbs[i].onclick = function() {
//hide all thumbs
document.getElementById('thumbnail_wrapper').classList.add('hidden');
//show large image (i got lazy and sliced)
document.getElementById('large' + this.id.slice(-1)).classList.remove('hidden');
};
}
for (var i = 0; i < large.length; i++) {
large[i].onclick = function() {
//hide large image
this.classList.add('hidden');
//show thumbs
document.getElementById('thumbnail_wrapper').classList.remove('hidden');
};
}
This creates a nice differentiation between styling with CSS, DOM structure for the contained elements and the javascript code that makes changes.

There are a lot of ways you could do this, and it would be very quick and easy in jQuery, but I'm not going to advocate that here because you clearly want to learn about javascript and jQuery can shield you from a lot of that. Try making your functions and function calls generic, like this:
<style type="text/css">
#largeimage_wrapper {visibility: hidden;}
</style>
</head>
<body>
<div id="thumbnail_wrapper">
<div id="thumbnail1"><img src="thumbnail1.jpg" onClick="get_big(1);"/></div>
<div id="thumbnail2"><img src="thumbnail2.jpg" onClick="get_big(2);"/></div>
<div id="thumbnail3"><img src="thumbnail3.jpg" onClick="get_big(3);"/></div>
...etc
</div>
<div id="largeimage_wrapper">
<div id="large1"><img src="thumbnail1.jpg" onClick="get_thumbs(1);"/></div>
<div id="large2"><img src="thumbnail2.jpg" onClick="get_thumbs(2);"/></div>
<div id="large3"><img src="thumbnail3.jpg" onClick="get_thumbs(3);"/></div>
...etc
</div>
</body>
javascript
function get_thumbs(id) {
document.getElementById('thumbnailwrapper').style.visibility='visible';
document.getElementById('large' + id).style.visibility='hidden';
}
function get_big(id) {
document.getElementById('thumbnailwrapper').style.visibility='hidden';
document.getElementById('large' + id).style.visibility='visible';
}

Related

More efficient way of highlighting selections?

I have about 30 options that a user can select. When they click the option it opens/highlights a content/html box for that selection and hides the others (similar to a picture lightbox but instead of thumbnails and main pic I need html).
I've found this Jquery code example: http://jsfiddle.net/EhtrR/1238/
<img id="img1"/>
<img id="img2"/>
<img id="img3"/>
<img id="img4"/>
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<div id="div4">4</div>
$("#img1").on('click', function() {
$("#div1").fadeIn();
$("#div2,#div3,#div4").fadeOut();
});
$("#img2").on('click', function() {
$("#div2").fadeIn();
$("#div1,#div3,#div4").fadeOut();
});
$("#img3").on('click', function() {
$("#div3").fadeIn();
$("#div1,#div2,#div4").fadeOut();
});
$("#img4").on('click', function() {
$("#div4").fadeIn();
$("#div1,#div2,#div3").fadeOut();
});
(Please note the images are just example. These can be div boxes or span.)
but as I'll need 20-30 of these options I was wondering how I can make it more efficient or do you suggest another way? I noticed on Mobile touch taps the clicks were fairly slow with the Jquery.
To DRY and simplify the logic you could put each set of elements in containers, grouped by their behaviour. Then apply common classes to them and relate them on click by their indexes. Try this:
let $contents = $('.content');
$('.trigger').on('click', e => {
let $target = $contents.eq($(e.target).index()).fadeToggle();
$contents.not($target).fadeOut();
});
.content { display: none; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="trigger-container">
<img src="01.jpg" class="trigger" />
<img src="02.jpg" class="trigger" />
<img src="03.jpg" class="trigger" />
<img src="04.jpg" class="trigger" />
</div>
<div class="content-container">
<div class="content">1</div>
<div class="content">2</div>
<div class="content">3</div>
<div class="content">4</div>
</div>
for(let i=0;i<=4;i++){
$("#img"+i).on('click', function() {
$("#div"+i).fadeIn();
for(var num=0; num<=4; num++)
{
if(num!=i)
{
$("#div"+num).fadeOut()
}
}
});
}

Could I get to an element using two ids?

Here's my code:
<div id='layer1'>
<div id='a'>
<div id='b'>
<div id='layer2'>
<div id='a'>
<div id='b'>
<div id='layer3'>
<div id='a'>
<div id='b'>
I want to try to get the element [a] of layer1.
Could I do this using pure javascript and withOUT jquery and other stuff?
An ID uniquely identifies one single element on the page. The behavior you described is more like "a class" inside of an ID:
document.querySelector("#counter-for-drinks .up-arrow")
and so if you want a different up-arrow, it is:
document.querySelector("#counter-for-burgers .up-arrow")
document.querySelector() is what is similar to jQuery $(" "). It also has the form document.querySelectorAll() for getting all matched elements.
Your HTML is missing closing tags. You can always validate your code here.
Also, you should use class instead of id.
<div id='layer1'>
<div class='a'></div>
<div class='b'></div>
</div>
<div id='layer2'>
<div class='a'></div>
<div class='b'></div>
</div>
<div id='layer3'>
<div class='a'></div>
<div class='b'></div>
</div>
You can use javascript to get elements:
document.querySelector("#layer1 .a")
var firstA = document.querySelectorAll('#layer1 #a');
var nodeString = '';
if (firstA.length > 0) {
for (var i = 0; i < firstA.length; i++) {
nodeString = nodeString + firstA[i].innerText + '<br/>';
}
}
document.getElementById('founded-nodes').innerHTML = nodeString;
#founded-nodes {
color: brown;
}
<div id='layer1'>
<div id='a'>layer1 aaa</div>
<div id='b'>layer1 bbb</div>
</div>
<div id='layer2'>
<div id='a'>layer2 aaa</div>
<div id='b'>layer2 bbb</div>
</div>
<div id='layer3'>
<div id='a'>layer3 aaa</div>
<div id='b'>layer3 bbb</div>
</div>
<div id="founded-nodes"></div>
As all said in above over comments and answers, one must use a single id on the same page, or else the use of classes is a must. But if you want to achieve this, you can have a look at code.

how can I show a div based on content in another div jQuery

I have multiple divs in html such:
<div class="litter">
<div class="litter-1">
<div class="status">Available</div>
<div class="available"><img /></div>
</div>
<div class="litter-2">
<div class="status">Available</div>
<div class="available"><img /></div>
</div>
</div>
The status text will vary based on user input. If the status is available the available class should not show. But if the status is unavailable then it should. The image is present all the time but only displaying if the status changes.
I can get the jQuery to either hide all of the images, or show them all, but not based on the html value of the status.
jQuery
if($('.litter > .status').html()==="Available") {
$(this).next('.available').hide();
} else {
$('.available').show();
}
Any help?
You could use a loop using jQuery .each():
// change selector to '.litter .status'
$('.litter .status').each(function() {
// loop through each .status element
// get partner img container .available
var imgContainer = $(this).parent().find('.available');
if ($(this).text() === "Available")
{
imgContainer.hide();
}
else
{
imgContainer.show();
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="litter">
<div class="litter-1">
<div class="status">Available</div>
<div class="available"><img src="https://via.placeholder.com/150/" alt="placeholder1" /></div>
</div>
<div class="litter-2">
<div class="status">Other status</div>
<div class="available"><img src="https://via.placeholder.com/150/" alt="placeholder2" /></div>
</div>
</div>
You can toggle a single class, status-available, and combine it with the adjacent sibling combinator to control the display of the image.
<!-- Image will show -->
<div class="status status-available">…</div>
vs.
<!-- Image will not show -->
<div class="status">…</div>
Example
/* Image is hidden by default */
.available > img {
display: none;
}
/* Adjacent sibling combinator in action */
.status-available + .available > img {
display: block;
}
<div class="litter">
<div class="litter-1">
<div class="status status-available">Available</div>
<div class="available">
<img src="http://placekitten.com/150/150" alt="Cute cat" />
</div>
</div>
<div class="litter-2">
<div class="status">Available</div>
<div class="available">
<img src="http://placekitten.com/150/150" alt="Cute cat" />
</div>
</div>
</div>
Ok, so Haldo put me on the right track, but in order to make it all come together with the string. Instead of if ($(this).text() === ("Available") I had to use this if ($(this).text().indexOf('Needs a Forever Home') > -1)
The rest of the code stays the same as Haldo's.

Change text in multiple divs with same class onclick [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I have a list of football matches and would like to replace all scores with "?-?" when pressing a button and toggle back to show the score when pressing again.
div {
display: table;
}
div div {
display: table-row;
}
div div div {
display: table-cell;
}
.score {
color: blue;
padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Hide scores!</button>
<br> <br>
<div class="table">
<div class="match">
<div class="team1">Manchester United</div>
<div class="score">1-1</div>
<div class="team2">Liverpool</div>
</div>
<div class="match">
<div class="team1">Juventus</div>
<div class="score">2-0</div>
<div class="team2">Inter Milan</div>
</div>
<div class="match">
<div class="team1">Real Madrid</div>
<div class="score">1-4</div>
<div class="team2">Barcelona</div>
</div>
<div class="match">
<div class="team1">Dortmund</div>
<div class="score">3-0</div>
<div class="team2">Bayern Munich</div>
</div>
<div class="match">
<div class="team1">PSG</div>
<div class="score">0-1</div>
<div class="team2">Marseille</div>
</div>
</div>
I have experimented with getElementById and innerHTML, but due to the large number of matches I would prefer to use getElementsByClassName instead. I've seen people recommending querySelectorAll() for this, but I can't get the scripts to work.
An alternative would be to run a script replacing all numbers with a question mark inside divs with the same class.
Please help me out by using this fiddle
Here's a solution that uses querySelector only to select the button and the .table element to toggle a class.
The rest is all CSS, so no looping is needed.
Note that this exchanges your .score text content for a data-score attribute.
document.querySelector("button")
.addEventListener("click", function() {
document.querySelector("div.table").classList.toggle("hide-score");
});
.table .score:after {
content: attr(data-score);
}
.table.hide-score .score:after {
content: "?-?";
}
<button>Hide scores!</button>
<br>
<br>
<div class="table">
<div class="match">
<div class="team1">Manchester United</div>
<div class="score" data-score="1-1"></div>
<div class="team2">Liverpool</div>
</div>
<div class="match">
<div class="team1">Juventus</div>
<div class="score" data-score="2-0"></div>
<div class="team2">Inter Milan</div>
</div>
<div class="match">
<div class="team1">Real Madrid</div>
<div class="score" data-score="1-4"></div>
<div class="team2">Barcelona</div>
</div>
<div class="match">
<div class="team1">Dortmund</div>
<div class="score" data-score="3-0"></div>
<div class="team2">Bayern Munich</div>
</div>
<div class="match">
<div class="team1">PSG</div>
<div class="score" data-score="0-1"></div>
<div class="team2">Marseille</div>
</div>
</div>
To support older browsers, you could instead keep the score as text content, but put it in a span with another <span>?-?</span> next to it, and then configure the CSS to hide the :first-child and show the rest as needed.
If you don't want to change your html code
$.each($('.score'), function(key, score) {
var score_text = $(score).text();
$(score).data('score', score_text)
})
$('button').click(function() {
if ($(this).data('hiding-score')) {
$(this).data('hiding-score', false);
$.each($('.score'), function () {
$(this).text($(this).data('score'));
});
} else {
$(this).data('hiding-score', true);
$('.score').text('?-?');
}
})
div { display:table; }
div div { display:table-row; }
div div div { display:table-cell; }
.score { color:blue; padding:10px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Hide scores!</button>
<br>
<br>
<div class="table">
<div class="match">
<div class="team1">Manchester United</div>
<div class="score">1-1</div>
<div class="team2">Liverpool</div>
</div>
<div class="match">
<div class="team1">Juventus</div>
<div class="score">2-0</div>
<div class="team2">Inter Milan</div>
</div>
<div class="match">
<div class="team1">Real Madrid</div>
<div class="score">1-4</div>
<div class="team2">Barcelona</div>
</div>
<div class="match">
<div class="team1">Dortmund</div>
<div class="score">3-0</div>
<div class="team2">Bayern Munich</div>
</div>
<div class="match">
<div class="team1">PSG</div>
<div class="score">0-1</div>
<div class="team2">Marseille</div>
</div>
</div>
Here is a fiddle with plain old Javascript.
But I have to admit, #SkinnyPete's way is way better and easier to understand ! You shouls use it if you're only to hide the score. This is the best way to go.
// Mandatory JS code
const score = document.getElementsByClassName('score')
const button = document.getElementById("hide")
const initialState = []
for(let i = 0; i < score.length; i++){
initialState.push({initial : score[i].innerHTML})
}
button.addEventListener('click', (e) => {
const dynamicScore = document.getElementsByClassName('score')
for(let i = 0; i < dynamicScore.length; i++){
if(dynamicScore[i].innerText === initialState[i].initial){
dynamicScore[i].innerHTML = "?-?"
}else{
dynamicScore[i].innerHTML = initialState[i].initial
}
}
})
i added an id "hide" to your button this works fine
The solution I would recommend is that you make use of data attributes on the divs to store the scores. i.e. <div class="score" data-for="1" data-against="1">1-1</div>. Then it's easier to toggle the values. Since you're using jQuery,
// Set the values to ?-?
$('.match .score').html('?-?');
// set the actual scores
$('.match .score').each(function(){
$(this).html($(this).data('for') + '-' + $(this).data('against'));
});
My solution:
I would use the temporary storage. U can set the values for each element with the data()-Method
//STORE DATA IN TEMP STORAGE
$( ".score" ).each(function( index ) {
$(this).data("score-temp", $(this).text());
});
On Click-Event I would add a class "hide-score" to distinguish between both states. And if hide-score is already set, than you reset the values from the temporary storage
$("button").click(function() {
if ($(".table").hasClass( "hide-score" )) {
$(".table").removeClass("hide-score");
//set VALUE FROM TEMP STORAGE
$( ".score" ).each(function( index ) {
var score_temp = $(this).data("score-temp" );
$(this).text(score_temp);
});
}
else {
$( ".score" ).text("?-?");
$(".table").addClass("hide-score");
}
});

css odd even not working with pseudo-elements

I have a container div names wrapper and it has several child divs named thumb
I want to apply css pseudo elements with the even and odd.
My codes are
<div class="wrapper">
<div class="col-half">
<div class="thumb">
...
</div>
</div>
<div class="col-half">
<div class="thumb">
...
</div>
</div>
<div class="col-half">
<div class="thumb">
...
</div>
</div>
<div class="col-half">
<div class="thumb">
...
</div>
</div>
</div>
And my css:
.wrapper:nth-child(even) .thumb:after{
//some codes
}
.wrapper:nth-child(odd) .thumb:after{
//some codes
}
But i am getting only odd styles.
Since the odd and even relationship is applied based on sibling index, you need to apply it on col-half as that is the repeated element.
Since your thumb element is the first child of its parent, it will only satisfy the odd selector
.wrapper .col-half:nth-child(even) .thumb:after {
content: 'x'
}
.wrapper .col-half:nth-child(odd) .thumb:after {
content: 'y'
}
<div class="wrapper">
<div class="col-half">
<div class="thumb">
...
</div>
</div>
<div class="col-half">
<div class="thumb">
...
</div>
</div>
<div class="col-half">
<div class="thumb">
...
</div>
</div>
<div class="col-half">
<div class="thumb">
...
</div>
</div>
</div>
You have a misunderstanding about :nth-child as it does not work as "nth child of this container" but as "am I the nth child of my parent?".
So you need to apply :nth-child(odd/even) to .col-half:
.col-half:nth-child(even) .thumb:after{
//some codes
}
.col-half:nth-child(odd) .thumb:after{
//some codes
}
The name for this selector has really caused many misunderstandings as it is too easy to misunderstand the way you did.
.col-half:nth-child(even) {
color: green;
}
.col-half:nth-child(odd) {
color: red;
}
Try like this: Demo
In your css, You are using the parent div for showing even and odd. Instead you need to use odd / even for child elements which repeats
.col-half:nth-child(even) .thumb{
background:#ccc;
}
.col-half:nth-child(odd) .thumb{
background:#f00;
}
Try This One
.wrapper .col-half:nth-child(2n) .thumb:after {
content: '';
}
.wrapper .col-half:nth-child(2n-1) .thumb:after {
content: '';
}

Categories

Resources