Better way to write jquery add/remove class - javascript

I'm not an expert on JS and jQuery, but I would like to improve my knowledge.
I made this code that works for me, but I'm sure it can be done better. can you help me and explain how to synthesize it?
It's a piece of a slideshow when a URL is activated via a button, some images disappear and another appears.
<script>
$(".green").click(function(e){
window.location = "#img_green";
$('#piz_green').css("display", "block");
$('#piz_army').css("display", "none");
$('#piz_red').css("display", "none");
$('#piz_white').css("display", "none");
$('#piz_blue').css("display", "none");
$('#piz_black').css("display", "none");
});
$(".army").click(function(e){
window.location = "#img_army";
$('#piz_green').css("display", "none");
$('#piz_army').css("display", "block");
$('#piz_red').css("display", "none");
$('#piz_white').css("display", "none");
$('#piz_blue').css("display", "none");
$('#piz_black').css("display", "none");
});
$(".red").click(function(e){
window.location = "#img_red";
$('#piz_green').css("display", "none");
$('#piz_army').css("display", "none");
$('#piz_red').css("display", "block");
$('#piz_white').css("display", "none");
$('#piz_blue').css("display", "none");
$('#piz_black').css("display", "none");
});
$(".white").click(function(e){
window.location = "#img_white";
$('#piz_green').css("display", "none");
$('#piz_army').css("display", "none");
$('#piz_red').css("display", "none");
$('#piz_white').css("display", "block");
$('#piz_blue').css("display", "none");
$('#piz_black').css("display", "none");
});
$(".blue").click(function(e){
window.location = "#img_blue";
$('#piz_green').css("display", "none");
$('#piz_army').css("display", "none");
$('#piz_red').css("display", "none");
$('#piz_white').css("display", "none");
$('#piz_blue').css("display", "block");
$('#piz_black').css("display", "none");
});
$(".black").click(function(e){
window.location = "#img_black";
$('#piz_green').css("display", "none");
$('#piz_army').css("display", "none");
$('#piz_red').css("display", "none");
$('#piz_white').css("display", "none");
$('#piz_blue').css("display", "none");
$('#piz_black').css("display", "block");
});
</script>
Thank you.

To improve this code we also can improve html a little. We can add some class to identify elements and controls and after that - we might need only 6 lines of js
Please try this
$(".your-button-class").click(function(e) {
const color = e.target.dataset.color;
window.location = "#img_" + color;
$('.your-div-class').css("display", "none");
$('div[data-color=' + color + ']').css("display", "block");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<button class="your-button-class" data-color="green">green</button>
<button class="your-button-class" data-color="army">army</button>
<button class="your-button-class" data-color="red">red</button>
<button class="your-button-class" data-color="white">white</button>
<button class="your-button-class" data-color="blue">blue</button>
<button class="your-button-class" data-color="black">black</button>
</div>
<div class="your-div-class" data-color="green">green</div>
<div class="your-div-class" data-color="army">army</div>
<div class="your-div-class" data-color="red">red</div>
<div class="your-div-class" data-color="white">white</div>
<div class="your-div-class" data-color="blue">blue</div>
<div class="your-div-class" data-color="black">black</div>

There is no need for JavaScript here as you can do that with basic CSS as follows.
Use proper links with anchors:
green
<!-- repeat for other colors -->
black
Then use the :target pseudo-class as follows:
#piz_green,
#piz_army,
#piz_red,
#piz_white,
#piz_blue,
#piz_black {
display: none;
}
#piz_green:target,
#piz_army:target,
#piz_red:target,
#piz_white:target,
#piz_blue:target,
#piz_black:target {
display: block;
}
And by adding a parent element, you can simplify it as follows:
#container > * {
display: none;
}
#container > *:target {
display: block;
}

Data attributes on the elements and a common class would make your life easier
var slides = $(".slide"); // reference all the slides
$("[data-action").on("click", function(e){ // bind the click
var btn = $(this); // button that was clicked
var color = btn.data("action"); // get the color
slides.attr("hidden", true); // hide all the slides
$("#piz_" + color).removeAttr("hidden"); // show the clicked color
window.location.hash = "img_" + color; // update the hash
});
[hidden] {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button data-action="green">Green</button>
<button data-action="red">Red</button>
<button data-action="blue">Blue</button>
<div class="slide_wrapper">
<div class="slide" id="piz_green">green</div>
<div class="slide" id="piz_red">red</div>
<div class="slide" id="piz_blue">blue</div>
</div>

function slideshow(image_id, block_id){
window.location = image_id;
$("[id^=piz_]").css("display", "none");
$(block_id).css("display", "block");
}
$(".green").click(function(e){
slideshow("#img_green", "#piz_green");
});

Here is the solution I would go with. First I would add an arbitrary data attribute, in this case, colour. Then I would add all my buttons with a corresponding data attribute. Then attach to the click event of those buttons and call the following code.
$('[data-action=toggle]').click(function(e){
$('div[data-color]:not([data-color=' + e.target.dataset.color + '])').hide();
$('div[data-color=' + e.target.dataset.color + ']').show();
})
a{
margin-right: .5em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-color="green">green</div>
<div data-color="red">red</div>
<div data-color="blue">blue</div>
<div data-color="pink">pink</div>
<div data-color="yellow">yellow</div>
Green
Red
Blue
Pink
Yellow

When I highly suggest the use of common classes in this case, you could always use comma , separator in you selectors with show()/hide() to simplify your code (a little) like :
$(".green").click(function(e) {
window.location = "#img_green";
$('#piz_green').show();
$('#piz_army,#piz_red,#piz_white,#piz_blue,#piz_black').hide();
});
$(".army").click(function(e) {
window.location = "#img_army";
$('#piz_army').show();
$('#piz_green,#piz_red,#piz_white,#piz_blue,#piz_black').hide();
});
$(".red").click(function(e) {
window.location = "#img_red";
$('#piz_red').show();
$('#piz_green,#piz_army,#piz_white,#piz_blue,#piz_black').hide();
});
$(".white").click(function(e) {
window.location = "#img_white";
$('#piz_white').show();
$('#piz_green,#piz_army,#piz_red,#piz_blue,#piz_black').hide();
});
$(".blue").click(function(e) {
window.location = "#img_blue";
$('#piz_blue').show();
$('#piz_green,#piz_army,#piz_red,#piz_white,#piz_black').hide();
});
$(".black").click(function(e) {
window.location = "#img_black";
$('#piz_black').show();
$('#piz_green,#piz_army,#piz_red,#piz_white,#piz_blue').hide();
});
Another suggestion with no need to change your HTML structure:
$(".green, .army, .red, .white, .blue, .black").click(function(e) {
var color = $(this).prop('class');
window.location = "#img_" + color;
$('[id^=piz_]').hide();
$('#piz_' + color).show();
});

You can consider attribute selector to hide all the element at once. Make sure to call hide() before show()
$(".green").click(function(e) {
window.location = "#img_green";
$('[id^=piz]').hide();
$('#piz_green').show();
});
$(".army").click(function(e) {
window.location = "#img_army";
$('[id^=piz]').hide();
$('#piz_army').show();
});
$(".red").click(function(e) {
window.location = "#img_red";
$('[id^=piz]').hide();
$('#piz_red').show();
});
$(".white").click(function(e) {
window.location = "#img_white";
$('[id^=piz]').hide();
$('#piz_white').show();
});
$(".blue").click(function(e) {
window.location = "#img_blue";
$('[id^=piz]').hide();
$('#piz_blue').show();
});
$(".black").click(function(e) {
window.location = "#img_black";
$('[id^=piz]').hide();
$('#piz_black').show();
});

You can store id of the image you want to show as custom data attribute with each button and then hide all images (by giving them a common class) with one line and show only the image you need by it's id from custom data attribute.
Example of button element:
<button data-slideshow-button="green">Green</button>
Example of slideshow element:
<div id="piz_green" class="slideshow-image"></div>
And then just run code like this as click handler:
$('[data-slideshow-button]').click(function(e){
var showId = $(e.currentTarget).data('slideshowButton');
window.location = '#img_' + showId;
$('.slideshow-image').hide();
$('#piz_' + showId).show();
});

As you did use piz_ for all classes in your HTML, you can easily use them in your JavaScript. For example, if you want to hide them all you can just type:
$('[class^=piz_]').hide();. This will hide all elements where the class starts with piz_.
Now I made a quick example with this in action. Please know I made just tile and a retry button to give you an example.
$("[class^=piz_]").click(function(){ // Make all div's with the class piz_* clickable
$('[class^=piz_]').hide(); // Hide all elements
var classAttr = '.'+$(this).attr("class"); // Get the class from the tile you clicked on
$(classAttr).show(); // Show all tiles with the same class
});
// This is just to get all tiles back and try it again.
$('.retry').click(function() {
$('[class^=piz_]').show();
});
.piz_green { background:green; }
.piz_blue { background:blue; }
.piz_red { background:red; }
.piz_orange { background:orange; }
div, button { width:100px; height:100px; }
.retry { display:block; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="piz_green"></div>
<div class="piz_blue"></div>
<div class="piz_red"></div>
<div class="piz_orange"></div>
<div class="piz_green"></div>
<button class="retry">
Retry!
</button>

Related

SlideDown() using JavaScript not working as intended

Thanks to #mplungjan for helping me complete my first query which can be found here: Remove div with button click using JavaScript
The code works as intended however when we tried to get the slideDown() function to work it looks a bit... laggy and then just pops up without the animation being completed as intended.
Would like some support to see how can this be fixed.
Find below working code:
$(function() {
var $original = $('#ValuWrapper'),
$crossButton = $('#cross'),
$content = $("#content");
$content.on("click", ".cross", function() {
if ($(this).is("#cross")) return false;
var $cross = $(this);
$(this).next().slideUp(400, function() {
$(this).remove();
$cross.remove();
});
});
$("#repeat").on("click", function() {
$content.append($crossButton.clone(true).removeAttr("id"));
$content.append(
$original.clone(true)
.hide() // if sliding
.attr("id",$original.attr("id")+$content.find("button.cross").length)
.slideDown("slow") // does not slide much so remove if you do not like it
);
});
});
#content { height:100%}
#cross { display: none;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div id="content">
<button type="button" class="buttonImgTop cross" id="cross">X</button>
<div id="ValuWrapper">
...content comes here... <br/>
</div>
</div>
<button type="button" class="buttonImg" id="repeat">Add</button>
Kindly use below updated code for animation.
$("#repeat").on("click", function() {
$content.append($crossButton.clone(true).removeAttr("id"));
$content.append(
$original.clone(true)
// if sliding
.attr("id",$original.attr("id")+$content.find("button.cross").length).hide());
// does not slide much so remove if you do not like it
$("#"+$original.attr("id")+$content.find("button.cross").length).slideDown("slow");//change
});
and remove #content { height:100%;}
When you clone the $original you should reset its height so jQuery knows what height its got to animate to.
E.G: $original.css('height', $(this).height())
See demo:
$(function() {
var $original = $('#ValuWrapper'),
$crossButton = $('#cross'),
$content = $("#content");
$content.on("click", ".cross", function() {
if ($(this).is("#cross")) return false;
var $cross = $(this);
$(this).next().slideUp(400, function() {
$(this).remove();
$cross.remove();
});
});
$("#repeat").on("click", function() {
$content.append($crossButton.clone(true).removeAttr("id"));
$content.append(
$original.clone(true)
.css('height', $(this).height())//set height
.hide() .attr("id",$original.attr("id")+$content.find("button.cross").length)
.slideDown("slow")
);
});
});
#content { height:100%;}
#cross { display: none;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div id="content">
<button type="button" class="buttonImgTop cross" id="cross">X</button>
<div id="ValuWrapper">
...content comes here...
</div>
</div>
<button type="button" class="buttonImg" id="repeat">Add</button>

jQuery/Javascript add/remove this.class on click

<script>
$(".image-popup").on('click', function() {
$(this).find(".myModal").addClass("modal-active");
$(".modal-active").css("display", "block");
});
$(".close").on('click', function() {
$(".modal-active").css("display", "none");
var myVar = $(this).closest(".image-popup");
myVar.find(".myModal").removeClass("modal-active");
$(".modal-active").css("display","none");
});
</script>
I am attempting to have a modal appear and then disappear when I click the close button. The problem is that the removeClass() will not work and the "display", "none" will not override the first click function. Any Help?
My guess from your question and your comment above is that the event from your second handler is bubbling up to your first handler:
$(".image-popup").on('click', function() {
$(this).find(".myModal")
.addClass("modal-active")
.show();
});
$(".close").on('click', function(evt) {
evt.preventDefault();
$(this).closest(".image-popup")
.find(".myModal")
.removeClass("modal-active");
.hide();
});
Try to prevent the event from bubbling out of the .close handler by using evt.preventDefault();
You can fix it with this simple solution:
HTML
<div class="image-popup">
<div class="show-modal btn btn-success">Show Modal</div>
<div class="myModal">
<div class="close btn btn-success">Close</div>
<p>My Modal is active</p>
</div>
</div>
CSS
.modal-active .myModal{
display: block;
}
.myModal{
display:none;
}
.close{
color:red;
display:block;
}
JS
$(function(){
$('.show-modal').click(function(){
$(this).parent().addClass('modal-active');
});
$('.close').click(function(){
$(this).closest('.image-popup').removeClass('modal-active');
});
});
See this fiddle for more details https://jsfiddle.net/a3yze54w/1/

OnFocusOut not working when UL loses focus

I need your help,
I can't seem, for the life of me, be able to figure as to why I cannot set the $("#fileno_list").css("display", "none"); Ie. when the user hasn't quite made a selection and decides to click elsewhere on the page. Then the dropdown box should close. (display: none).
Here's a picture of the problem:
Here's the code in Question:
<script type="text/javascript">
$(document).ready(function() {
$("#fileno_list ul").focusout(function() {
$(this).css("display", "none");
});
});
function test() {
var rs_count = 3
if (rs_count > 1) {
for (var x = 0; x < rs_count; ++x) {
$("#fileno_list").append('<li>'+x+'</li>');
}
$("#fileno_arrow").css("display", "block");
}
$("#fileno_arrow").click(function() {
$("#fileno_list").css("display", "block");
});
$("#fileno_list li").click(function(e) {
var select = $(this).closest('#fileno_list')
select.find(".selected").removeClass('selected');
$(this).addClass('selected');
$("#fileno").val( $.trim( $(this).html() ) )
$("#fileno_list").css("display", "none");
});
$("#fileno").val( $("#fileno_list li").eq(0).html() )
}
</script>
Here is the HTML Markup:
<div class="field_container">
<div class="field_wrapper"><input type="text" class="field" id="fileno"></div>
<div id="fileno_arrow"></div>
<ul id="fileno_list"></ul>
</div>
<br>
<br>
<input type="button" onclick="test()" value="click me">
<br>
Assuming your select tag has an id, you can use event object to check which element was clicked and show/hide based on that.
$(document).click(function(e) {
if(e.target.id === "idOfSelect")
$("#idOfSelect").show();
});

Shift up div and fade in on option selection

Here's a jsfiddle that I found.
HTML
<div class="container">
<header>
<ul class="sidenav">
<li><h2><a data-region="nav-1" href="#"><span class="title">About</span></a></h2></li>
<li><h2><a data-region="nav-2" href="#"><span class="title">Services</span></a></h2></li>
</ul>
</header>
<div id="nav-1" class="infozone z1"><p>Hello I'm box 1.</p></div>
<div id="nav-2" class="infozone z2"><p>Hello I'm box 2.</p></div>
CSS
.infozone{
float:left;
position:absolute;
height:400px;
width:800px;
display:none;
}
.z1 {
background-color: blue;
}
.z2 {
background-color: red;
}
JS
$('.sidenav a').click(function(){
$('.infozone').fadeOut(550);
var region = $(this).attr('data-region');
$('#' + region).fadeIn(550);
})
What I'm trying to do is...
Instead of regular links, they will be < option >s
If a user chooses a certain option, the div that's related to that
option will fade in while moving up 5px. If there was a div that
faded in before, that div would fade out while moving down 5px.
Here is an updated jsfiddle. Unfortunately, the div's are not fading in/out, and on top of that, I'm not really sure how to add the "moving up/down" effect.
Any help is appreciated!
You are binding click event on option, which doesn't work that way. You need to listen to the change event of the select element.
Try:
$('#stateList').change(function(){
var region = $(this).find(':selected').data('region'); //get the data value of the selected option
$('.state').fadeOut(550);
$('#' + region).fadeIn(550);
});
Fiddle
For your question on animating the margin you can use the callback of fadeOut to achieve this.
$('#stateList').change(function () {
var region = $(this).find(':selected').data('region');
var $visible = $('.state:visible');
if ($visible.length) $visible.animate({
'margin-top': '5px'
}, 550).fadeOut(550, function () {
$('#' + region).fadeIn(550).animate({
'margin-top': '0px'
}, 550);
});
else $('#' + region).fadeIn(550).animate({
'margin-top': '0px'
}, 550);
})
Fiddle
You need to bind event with select instead of option. Try this
$('#stateList').change(function () {
var region = $(this).find(':selected').data('region');
$('.state').fadeOut(550);
$('#' + region).fadeIn(550);
})
Demo
Working DEMO
Try this
$('#stateList').change(function(){
$('.state').fadeOut(550);
var region = $("#stateList option:selected").data('region');
$('#' + region).fadeIn(550);
})

How to target an element under an other element?

I can click on a button (button A) and with some jquery it makes an image visible on this button at the exact same position (position:absolute).
See this fiddle
I would like to click again on this button (button A) to hide the image but i don't know how because the image is over the button.
I've found other solutions (more jquery or use an invisible image button) but i would like to find a more elegant way.
How can i target the button which is under the image ?
Jquery Code :
$(document).ready(function() {
$('#button').css('cursor', 'pointer');
$('#button').click(function() {
if ($('#image_1').css('visibility') == 'hidden') {
$('#image_1').css('visibility', 'visible');
} else {
$('#image_1').css('visibility', 'hidden');
}
});
});
CSS :
#button
{
width:100px;
background-color:#666666;
height:25px;
position:absolute;
left:10px;
top:10px;
}
#image_1
{
width:100px;
background-color:#666666;
height:25px;
position:absolute;
left:10px;
top:10px;
visibility:hidden;
}
html
<div id=main>
<div id="button">
</div>
<div id="image_1">Hello World!
</div>
</div><!-- main -->
#closure #Justin John #Jai #Robz #Adam #Happy Singh #Ross Dargan #Wouter de Kort #Viral Patel #Ruben Stolk
Thank you for all your interesting answers. It's difficult to choose because there are some really good ones. I've chosen Adam's answer because it's the simplest (juste use toglle jQuery and a css class). If you think your answer is better, please post your arguments here.
I binded the click event to both the #button and the #image by adding the class button to them both; when you click either, it will show/hide the image.
Also if you use display: none instead of visibility: hidden you can use jQuery's toggle(), which saves you a few lines of code.
see the fiddle
$(document).ready(function() {
$('.button').click(function() {
$('#image_1').toggle();
});
});
How about something like:
$(document).ready(function() {
$('#button').css('cursor', 'pointer');
$('#button').click(function() {
$('#image_1').show();
});
$('#image_1').click(function() {
$(this).hide();
});
});​
Check this demo: http://jsfiddle.net/viralpatel/R5MVD/1/
It is easier to put the image div inside your button div. You can also use the jQuery toggle function to show/hide the image.
<div id=main>
<div id="button">
<div id="image_1">Hello World!
</div>
</div>
</div><!-- main --> ​
$(document).ready(function() {
$('#button').css('cursor', 'pointer');
$('#button').click(function() {
$('#image_1').toggle();
})
});​
Here is a fiddle that shows it: http://jsfiddle.net/jBaWN/2/
This fiddle shows how it can be done easliy: http://jsfiddle.net/33aus/1/
Note I changed the image's css to display:none.
$(document).ready(function() {
$('#button').css('cursor', 'pointer');
$('#button').click(toggleVisiblity);
$('#image_1').click(toggleVisiblity);
});
function toggleVisiblity()
{
$('#button').toggle();
$('#image_1').toggle();
}​
See the updated fiddle http://jsfiddle.net/eCCR6/8/
$(document).ready(function() {
$('#button').css('cursor', 'pointer');
$('#button').click(function() {
if ($('#image_1').css('visibility') == 'hidden') {
$('#image_1').css('visibility', 'visible');
}
});
$('#image_1').click(function() {
if ($('#image_1').css('visibility') == 'visible') {
$('#image_1').css('visibility', 'hidden');
}
});
});
just change your javascript to
$(document).ready(function() {
$('#button').css('cursor', 'pointer');
$('#button').click(function() {
if ($('#image_1').css('visibility') == 'hidden') {
$('#image_1').css('visibility', 'visible');
} else {
$('#image_1').css('visibility', 'hidden');
}
});
$('#image_1').click(function(){
$('#image_1').css('visibility', 'hidden');
});
});
I think you have to trigger the button on mousedown on img 1 try this one:
$(document).ready(function() {
$('#button').css('cursor', 'pointer');
$('#button').click(function() {
if ($('#image_1').css('visibility') == 'hidden') {
$('#image_1').css('visibility', 'visible');
} else if ($('#image_1').css('visibility') == 'visible') {
$('#image_1').css('visibility', 'hidden');
}
$('#image_1').mousedown(function(){
$('#button').click();
});
});
});
Here we have done 1 else if check and trigger the button click on mousedown event on #image_1.
checkout the fiddle: http://jsfiddle.net/eCCR6/16/
You can also combine both selectors like this in fiddle.
$('#button, #image_1').click(function() {
// Your code
});
See the fiddle http://jsfiddle.net/eCCR6/2/.
I have created the function like this, and bound to both:
function clickFn() {
if ($('#image_1').css('visibility') == 'hidden') {
$('#image_1').css('visibility', 'visible');
} else {
$('#image_1').css('visibility', 'hidden');
}
}
Another model is to bind your event to the parent div main.
See the fiddle http://jsfiddle.net/eCCR6/18/
Use the jquery .prev() or .next() function
Instead of causing the image to become responsive to clicking (which does not work when there are multiple buttons below the image), you could make the image non-responsive to clicks using the pointer-events CSS property. It would look something like this:
#image_1
{
pointer-events: none;
}
See fiddle: http://jsfiddle.net/eCCR6/31/
This will cause clicks to pass through the image directly to the button below.
The disadvantage to this method is that the image no longer responds to mouse movement, but in this case, that's okay.

Categories