jQuery code refactoring help needed - javascript

An update to before, here's what I'm dealing with:
<body>
<div class="header"> <img class="imgLogo" src="img/vegtablelogo.jpg"> </div>
<div id="thumbsContainer">
<div class="thumb" id="carrotThumb"> <img id="showCarrot" class="imgThumb" src="img/carot.jpg" onClick=setupVeg("showCarrot", "carrotBig") /> </div>
<div class="hidden" id="carrotBig"> <img class="imgBig" src="img/carot.jpg" /> </div>
<div class="thumb" id="brocThumb"> <img id="showBroc" class="imgThumb" src="img/brocoli.jpg" onClick=setupVeg("showBroc", "brocBig") /> </div>
<div class="hidden" id="brocBig"> <img class="imgBig" src="img/brocoli.jpg" /> </div>
</div>
<!-- end thumbs container -->
<script>
var active = "";
function setupVeg(thumbVeg, hiddenVeg) {
$("#" + thumbVeg).click(function() {
if (active != hiddenVeg) {
$("div.hidden").hide("fast");
$("#" + hiddenVeg).show("fast", function() {});
active = hiddenVeg;
}
else {
$("div.hidden").hide("fast");
active="";
}
});
}
$("div.hidden").click(function () {
$("div.hidden").hide("fast");
isAnyBig=false;
});
</script>
</body>
This code is not working unfortunately. I have borrowed from suggested solution below.
Would be nice if it did work!
Any suggestions, most welcome.

I don't think you need any of the flags or the if conditions really. I think your logic is:
toggle carrotBig whenever showCarrot
is clicked.
hide div.hidden whenever showCarrot is clicked.
So all you need is:
$("#showCarrot").click(function () {
$("#carrotBig").toggle("fast");
$("#div.hidden").hide();
});
.toggle will handle one of your flags (isCarrotBig) and .hide() won't do anything if div.hidden is already hidden, so that takes care of your isAnyBig flag.
Now.. let's make that work with broc as well...
function setupVegetable(showId, toggleId) {
$("#" + showId).click(function () {
$("#" + toggleId).toggle("fast");
$("#div.hidden").hide();
});
}
setupVegetable("showCarrot", "carrotBig");
setupVegetable("showBroc", "brocBig");
If you're interested, you can refactor it FURTHER so you don't need to supply the IDs for each of the vegetables. I'll need to see your HTML markup though.

Ok I'll post a new answer in response to the edit.
Points worth noting:
Removed divs surrounding the imgs - they are unnecessary and complicate the relationship between the thumnnails and the large images.
Removed onclick attribute from within HTML - you will be attaching the event handlers in the JS so this is not needed.
Since the relationship between the thumbnails and the large images is quite obvious (the large images is just the next element) you don't need IDs to identify ANY of them. All you need is a class on the thumbnails.
Since we're not using IDs, only classes, you can add as many vegetables as you want without touching the JS
Your code modified:
<body>
<div class="header"> <img class="imgLogo" src="img/vegtablelogo.jpg"> </div>
<div id="thumbsContainer">
<img class="imgThumb" src="img/carot.jpg" />
<img class="imgBig hidden" src="img/carot.jpg" />
<img class="imgThumb" src="img/brocoli.jpg" />
<img class="imgBig hidden" src="img/brocoli.jpg" />
</div>
<!-- end thumbs container -->
<script>
$("#thumbsContainer .imgThumb").click(function () {
var thisImgBig = $(this).next();
// Hide all imgBigs, except for this one
$("#thumbsContainer .imgBig").not(thisImgBig[0]).hide();
// Toggle this imgBig
thisImgBig.toggle();
});
$("#thumbsContainer .imgBig").click(function () {
// Hide this imgBig
$(this).hide();
});
</script>
</body>

create a function and reuse it....something like:
/**
* document here....
*/
var toggleElements = function() {
// your code here
}
and then
$("#whatever").click(toggleElements);

Personally I would suggest creating a simple jQuery plugin. Something like so:
(function($){
$.fn.big = function(options) {
var defaults = {
target: '#carrotBig',
};
var options = $.extend(defaults, options);
return this.each(function() {
$(this).click(function () {
isBrocBig=false;
if (isCarrotBig == false && isAnyBig == false) {
$(options.target).show("fast", function() {});
isCarrotBig=true;
isAnyBig=true;
}
else if (isCarrotBig == true) {
$(options.target).hide("fast");
isCarrotBig=false;
isAnyBig=false;
}
else if (isCarrotBig == false && isAnyBig == true) {
$("div.hidden").hide("fast");
$(options.target).show("fast", function() {});
isCarrotBig=true;
}
else {
$("div.hidden").hide("fast");
isCarrotBig=false;
isAnyBig=false;
}
});
});
};
})(jQuery);
Then you just call it with something like so:
$("#showCarrot").big({target: '#carrotBig'})
Your next step should be to investigate whether you can get rid of the global variables or not.

Ok I have found a neat(ish) sollution, dependent on each hidden DIV being the .next() one. If it isn't it won't work but should be fine generally though. Hacked!
<div class="header"> <img class="imgLogo" src="img/vegtablelogo.jpg"> </div>
<div id="thumbsContainer">
<div class="thumb" id="carrotThumb"> <img id="showCarrot" class="imgThumb" src="img/carot.jpg" /> </div>
<div class="hidden" id="carrotBig"> <img class="imgBig" src="img/carot.jpg" /> </div>
<div class="thumb" id="brocThumb"> <img id="showBroc" class="imgThumb" src="img/brocoli.jpg" /> </div>
<div class="hidden" id="brocBig"> <img class="imgBig" src="img/brocoli.jpg" /> </div>
</div>
<!-- end thumbs container -->
<script>
var active = "";
$("div.thumb").click(function() {
var thumbVeg = $(this).attr("id");
var hiddenVeg = $(this).next().attr("id");
setupVeg(thumbVeg, hiddenVeg);
});
function setupVeg(thumbVeg, hiddenVeg) {
if (active != hiddenVeg) {
$("div.hidden").hide("fast");
$("#" + hiddenVeg).show("fast", function() {});
active = hiddenVeg;
}
else {
$("div.hidden").hide("fast");
active="";
}
}
$("div.hidden").click(function () {
$("div.hidden").hide("fast");
});
</script>

Related

addClass dont works on conditional

I come to you with my next problem xd
This is my js:
$(document).ready(function(e) {
let imagesContainer = $(".slider__imageContainer");
let index = 0;
for(let item of imagesContainer) {
if(item == imagesContainer[0]) {
item.addClass("d-block");
}
else {
imagesContainer.addClass("d-none")
}
}
})
Why dont work the "addClass("d-block") function - but my "else" works fine.
and this is my HTML
<body>
<div class="slider">
<div class="slider__imageContainer">
<img src="images/cat-5852139_640.jpg" alt="" class="slider__imageContainer--image">
</div>
<div class="slider__imageContainer">
<img src="images/kingfisher-6146356_640.jpg" alt="" class="slider__imageContainer--image">
</div>
<div class="slider__imageContainer">
<img src="images/meerkats-6153748_640.jpg" alt="" class="slider__imageContainer--image">
</div>
</div>
this is not the element you are thinking, it refers to the HTMLDocument object. You can try
$(item).addClass("d-block");
You need to use item instead of this. Also your code could be optimised further from:
for (let item of imagesContainer) {
if (item == imagesContainer[0]) {
item.addClass("d-block");
} else {
imagesContainer.addClass("d-none")
}
}
to:
imagesContainer.addClass("d-none");
imagesContainer[0].addClass("d-block");

How to add css code in onmouseover="hover('')" [JS]

I can't adjust my text to be center aligned. I tried to put css code in onmouseover="hover('')" but it doesn't work. What is the get around for this?
Middle circle with id="content" that changes the tag on hover
<div id="circle">
<p id="content">
<b><span>Services</span></b>
</p>
</div>
JS Code that I included in the html tag to change content on hover
<a href="">
<div onmouseover="hover('<b>BPO</b>')" onmouseout="hover('<b>Services</b>')" class="scaling" id="circle-2">
<img src="/static/img/2.png" onmouseover="this.src='/static/img/2b.png'" onmouseout="this.src='/static/img/2.png'" style="margin-top:5px;" width=100px/>
</div>
</a>
<a href="">
<div onmouseover="hover('<b>Web Development</b>')" onmouseout="hover('<b>Services</b>')" class="scaling" id="circle-3">
<img src="/static/img/4.png" onmouseover="this.src='/static/img/4b.png'" onmouseout="this.src='/static/img/4.png'" style="margin-top:5px;" width=100px/>
</div>
</a>
JS Code that changes the content of the <p> tag
function hover(description) {
console.log(description);
document.getElementById('content').innerHTML = description;
}
everything is working properly but I can't adjust the text to be in the center regard less of the <p> tag length .
The main question is how do i add css code in onmouseover="hover('')"
What i want it to look like
what it looks like
Your code really needed a lot of cleaning up.
You should separate the HTML, CSS and JavaScript. After doing this, debugging is SO much easier and the code is much simpler to follow.
In addition, you had a great deal of duplication in your code. Again, using CSS and JavaScript can remove that redundancy. For example, styling is done with CSS, not HTML. Tags like <b> are deprecated and should no longer be used. By creating CSS styles that incorporate font-weight:bold and applying those styles properly, we can get rid of all the <b> and </b> tags.
// Get all DOM references:
var content = document.getElementById('content');
var cir2 = document.getElementById("circle-2");
var cir3 = document.getElementById("circle-3");
var img1 = document.getElementById("img1");
var img2 = document.getElementById("img2");
// Attach event handlers:
cir2.addEventListener("mouseover", function(){ hover('BPO') });
cir2.addEventListener("mouseout", function(){ hover('Services') });
cir3.addEventListener("mouseover", function(){ hover('Web Development') });
cir3.addEventListener("mouseout", function(){ hover('Services') });
img1.addEventListener("mouseover", function(e){ changeSource(e,'http://plumseattle.com/wp-content/uploads/2016/01/linkedin-logo.jpg') });
img1.addEventListener("mouseout", function(e){ changeSource(e, 'https://cdn3.iconfinder.com/data/icons/free-social-icons/67/facebook_circle_color-256.png') });
img2.addEventListener("mouseover", function(e){ changeSource(e, 'http://seeklogo.com/images/S/snapchat-logo-2D9C3E7ADA-seeklogo.com.png') });
img2.addEventListener("mouseout", function(e){ changeSource(e, 'https://www.seeklogo.net/wp-content/uploads/2011/06/Twitter-icon-vector-400x400.png') });
function hover(description) {
//console.log(description);
content.textContent = description;
}
function changeSource(evt, source){
evt.target.src = source;
}
content > span { font-weight: bold;}
.scaling { font-weight:bold; }
.img { margin-top:5px;width:100px; }
<div id="circle">
<p id="content">
<span>Services</span>
</p>
</div>
<a href="">
<div class="scaling" id="circle-2">
<img id="img1"
src="https://cdn3.iconfinder.com/data/icons/free-social-icons/67/facebook_circle_color-256.png"
class="img">
</div>
</a>
<a href="">
<div class="scaling" id="circle-3">
<img id="img2"
src="https://www.seeklogo.net/wp-content/uploads/2011/06/Twitter-icon-vector-400x400.png"
class="img">
</div>
</a>
Typically, if you want some element to listen to "mouseover" event, the best way to go is to use EventTarget#addEventListener. Just like this:
const node = document.getElementById('hover');
node.addEventListener('mouseover', () => {
node.innerText = `Last time mouseover'd at ${new Date()}.`;
});
So, now, you need to update children of #content and src attribute of an image under mouse cursor.
The HTML would look like this:
<p id="content">
Services
</p>
<a href="">
<div class="scaling" id="circle-2">
<img src="/static/img/2.png" />
</div>
</a>
<a href="">
<div class="scaling" id="circle-3">
<img src="/static/img/2.png" />
</div>
</a>
while JS code would look like this:
const content = document.getElementById('content');
const circle2 = document.getElementById('circle-2');
const circle3 = document.getElementById('circle-3');
circle2.addEventListener('mouseover', () => {
circle2.children[0].src = '/static/img/2b.png';
content.innerText = 'BPO';
});
circle2.addEventListener('mouseout', () => {
circle2.children[0].src = '/static/img/2.png';
content.innerText = 'Services';
});
circle3.addEventListener('mouseover', () => {
circle3.children[0].src = '/static/img/4b.png'
content.innerText = 'Web Development';
});
circle3.addEventListener('mouseout', () => {
circle3.children[0].src = '/static/img/4.png'
content.innerText = 'Services';
});
(check out this fiddle).

Jquery data attribute value equals

Below are my requirements.. i tried in below way. it doesnt work for me. Please let me know what is missed out. Thanks
if data-block = 1, add data-rewardpoints = 300
if data-block = 2, add data-rewardpoints = 400
if data-block = 3, add data-rewardpoints = 500
HTML:
<div class="ir_image_holder">
<img class="ir_img_src" src="1.jpg" data-block="1" data-rewardpoints="" />
</div>
<div class="ir_image_holder">
<img class="ir_img_src" src="2.jpg" data-block="2" data-rewardpoints="" />
</div>
<div class="ir_image_holder">
<img class="ir_img_src" src="3.jpg" data-block="3" data-rewardpoints="" />
</div>
JS:
if ($('.ir_image_holder .ir_img_src').data('block')===1) {
$('.ir_image_holder .ir_img_src').attr('data-rewardpoints', '300');
} else if ($('.ir_image_holder .ir_img_src').data('block')===2) {
$('.ir_image_holder .ir_img_src').attr('data-rewardpoints', '400');
} else if ($('.ir_image_holder .ir_img_src').data('block')===3) {
$('.ir_image_holder .ir_img_src').attr('data-rewardpoints', '500');
}
To achieve this you need to loop over all the .ir_img_src elements individually. Right now your code is setting all the elements data() attributes based on the first element of the set.
You can also tidy the logic by holding all the values to set in an object keyed by the block. Try this:
var data = { 1: 300, 2: 400, 3: 500 }
$('.ir_img_src').each(function() {
$(this).attr('data-rewardpoints', data[$(this).data('block')]);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="ir_image_holder">
<img class="ir_img_src" src="1.jpg" data-block="1" data-rewardpoints="" />
</div>
<div class="ir_image_holder">
<img class="ir_img_src" src="2.jpg" data-block="2" data-rewardpoints="" />
</div>
<div class="ir_image_holder">
<img class="ir_img_src" src="3.jpg" data-block="3" data-rewardpoints="" />
</div>
Note that it's considered better practice to use the setter of data() instead of attr(), where possible. I've left your code as-is here, as there are certain cases where you have to use attr() to set the data attribute.
Do some thing like this
// Get all matched element
var elem = $('.ir_image_holder .ir_img_src');
// loop through each o fthem to get the data-block value
$(elem).each(function(e,v){
if($(this).data('block')===1){
// assign the data-reward point here
$(this).attr('data-rewardpoints',300);
}
// rest of code
})
try iterating over all elements
$('.ir_image_holder .ir_img_src').each(function() {
if($( this ).data('block') == "1") {
$( this ).attr('data-rewardpoints', '300');
}
else if($( this ).data('block') == "2") {
$( this ).attr('data-rewardpoints', '400');
}
else if($( this ).data('block') == "3") {
$( this ).attr('data-rewardpoints', '500');
}
});
Your selector selects all elements that match it and not a single one, which is the expectation of the JS snippet you've provided.
I assume you want the image to be clicked and then to perform the operation in your JS snippet. Here's how you can do it:
$('.ir_image_holder .ir_img_src').on('click', function () {
var $el = $(this);
if ($el.data('block')===1) {
$el.attr('data-rewardpoints', '300');
} else if ($el.data('block')===2) {
$el.attr('data-rewardpoints', '400');
} else if ($el.data('block')===3) {
$el.attr('data-rewardpoints', '500');
}
});
If you're just trying to initialize them then iterate over all selected elements.
$('.ir_image_holder .ir_img_src').each(function () {
var $el = $(this);
if ($el.data('block')===1) {
$el.attr('data-rewardpoints', '300');
} else if ($el.data('block')===2) {
$el.attr('data-rewardpoints', '400');
} else if ($el.data('block')===3) {
$el.attr('data-rewardpoints', '500');
}
});
When you just want to compare similar values, why not use switch instead of if
$('.ir_img_src').each(function(e,v){
var me = $(this);
var db = parseInt($(this).attr('data-block'));
switch(db)
{
case 1 : me.attr('data-rewardpoints', '300');
break;
case 2 : me.attr('data-rewardpoints', '400');
break;
case 3 : me.attr('data-rewardpoints', '500');
break;
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="ir_image_holder">
<img class="ir_img_src" src="1.jpg" data-block="1" data-rewardpoints="" />
</div>
<div class="ir_image_holder">
<img class="ir_img_src" src="2.jpg" data-block="2" data-rewardpoints="" />
</div>
<div class="ir_image_holder">
<img class="ir_img_src" src="3.jpg" data-block="3" data-rewardpoints="" />
</div>

Add Class to Following Element

I had a look out on the interwebs for a jQuery image gallery and couldn't find one that suited what I wanted to do. So I, ended up creating one myself and am trying to figure out how to get the prev and next buttons to work.
<div class="gallery portrait">
<nav>
<div class="close"></div>
<div class="prev"></div>
<div class="next"></div>
</nav>
<div class="cover">
<img src="image.jpg">
</div>
<ul class="thumbs">
<li class="thumb">
<img src="image.jpg">
</li>
...
</ul>
</div>
I'm also using a bit of jQuery to add a class of .full to the .thumb a element, which makes the thumbnails go fullscreen.
$( ".thumb a" ).click(function() {
$( this ).toggleClass( "full" );
$( "nav" ).addClass( "show" );
});
Now I can't work out this next bit, I need a way when the .prev or .next buttons are clicked for it to remove the class of .full from the current element and add it to the next or previous .thumb a element, depending on which was clicked.
I've got a demo setup here: http://codepen.io/realph/pen/hjvBG
Any help is appreciated, thanks in advance!
P.S. If this turns out well, I plan on releasing it for free. I guess you can't have too many jQuery image galleries, eh?
You can use $.next() and $.prev():
$(".prev").click(function () {
var current = $('.full');
current.prev('.thumb').addClass('full');
current.removeClass('full');
return false; // stop propagation; prevents image click event
});
$(".next").click(function () {
var current = $('.full');
current.next('.thumb').addClass('full');
current.removeClass('full');
return false; // stop propagation; prevents image click event
});
I suggest the following additions to your code to handle wrapping around with your next and previous links:
$(".next").click(function (event) {
navigate("next");
return false;
});
$(".prev").click(function (event) {
navigate("prev");
return false;
});
function navigate(operation) {
var $thumbs = $(".thumb"),
$full = $thumbs.find("a.full").closest(".thumb"),
$next;
$thumbs.find('a').removeClass('full');
if (operation == 'prev' && $full.is($thumbs.first()))
$next = $thumbs.last();
else if (operation == 'next' && $full.is($thumbs.last()))
$next = $thumbs.first();
else
$next = $full[operation]();
$next.find('a').click();
}
Here is a forked CodePen.
Something like this will get you started, but what you're wanting to do takes a little time to get just right.
<script type="text/javascript">
var imgSrcs = ['/imgs/this.jpg', '/imgs/will.jpg', '/imgs/work.jpg', '/imgs/just.jpg', '/imgs/fine.jpg'];//img url loaded into an array
var btnPrev = document.getElementById('prev'),
btnNext = document.getElementById('next'),
cover = document.getElementById('cover'),
thumb = document.getElementById('thumb'),
currImgIx = 0;
btnPrev.onclick = function () {
if (currImgIx === 0) { return; };
currImgIx--;
cover.src = imgSrcs[currImg];
thumb.src = imgSrcs[currImgIx];
};
btnNext.onclick = function () {
if (currImgIx === imgSrcs.length - 1) { return; };
currImgIx++;
cover.src = imgSrcs[currImgIx];
thumb.src = imgSrcs[currImgIx];
};
</script>
<div class="gallery portrait">
<nav>
<div class="close">X</div>
<div id="prev" class="prev">Prev</div>
<div id="next" class="next">Next</div>
</nav>
<div class="cover">
<img id="cover" src="image.jpg">
</div>
<ul class="thumbs">
<li class="thumb">
<img id="thumb" src="image.jpg">
</li>
...
</ul>
</div>

If class also is class then.. move active class on click

(New at jQuery)
Trying to write a function that moves an active class along as an arrow is clicked..
html
<div id="steps">
<a href="#1" data-ref="dynamic-tabs slider-id">
<div class="step step-1 active">
<div class="step-img">
<img width="175" height="120" src="http://site.com/img.png">
</div>
<div class="step-title">Schedule Online or Wave Down a Biker</div>
<div class="step-over"></div>
</div>
</a>
<a href="#2" data-ref="dynamic-tabs slider-id">
<div class="step step-2">
<div class="step-img">
<img width="175" height="120" src="http://site.com/img.png">
</div>
<div class="step-title">We Bike to & Clean Your Car</div>
<div class="step-over"></div>
</div>
</a>
<a href="#3" data-ref="dynamic-tabs slider-id">
<div class="step step-3">
<div class="step-img">
<img width="175" height="120" src="http://site.com/img.png">
</div>
<div class="step-title">Come Back to a Clean Car</div>
<div class="step-over"></div>
</div>
</a>
</div>
<div class="nav-right" data-dir="next" title="Slide right">
right »
</div>
jQuery I'm trying
$(".nav-right a").click(function() {
if( $(".step-1").is('.active') ) {
$(".step-1").removeClass("active");
$(".step-2").addClass("active");
}
});
$(".nav-right a").click(function() {
if( $(".step-2").is(".active") ) {
$(".step-2").removeClass("active");
$(".step-3").addClass("active");
}
});
$(".nav-right a").click(function() {
if( $(".step-3").is(".active") ) {
$(".step-3").removeClass("active");
$(".step-1").addClass("active");
}
});
The problem seems to be that you create 3 (sic!) event handlers which fire sequentially when you click the link.
The first handler, as step 1 is active, sets step 2 to active.
The second handler, as step 2 is now active, sets step 3 to active
The third handler, as step 3 is now active, sets step 1 to active again.
In the end, nothing has happened.
Solution: Use only one event handler, and if-else-statements instead of only if-statements:
$(".nav-right a").click(function() {
if( $(".step-1").is('.active') ) {
$(".step-1").removeClass("active");
$(".step-2").addClass("active");
} else if( $(".step-2").is(".active") ) {
$(".step-2").removeClass("active");
$(".step-3").addClass("active");
} else if( $(".step-3").is(".active") ) {
$(".step-3").removeClass("active");
$(".step-1").addClass("active");
}
});
Of course, we can do much better and write a generic function, which also does not need the step-N classes:
var rotatedElements = $(".step");
$(".nav-right a").click(function() {
var cur = rotatedElements.filter(".active");
cur.removeClass("active");
var index = rotatedElements.index(cur) + 1;
if (index >= rotatedElements.length)
index = 0;
rotatedElements.eq(index).addClass("active");
});
As suggested in comment by theScientist you should use only one event handler.
$(".nav-right a").click(function() {
if( $(".step-1").is('.active') ) {alert('1');
$(".step-1").removeClass("active");
$(".step-2").addClass("active");
return;
}
if( $(".step-2").is(".active") ) {alert('2');
$(".step-2").removeClass("active");
$(".step-3").addClass("active"); return;
}
if( $(".step-3").is(".active") ) {alert('3');
$(".step-3").removeClass("active");
$(".step-1").addClass("active"); return;
}
});
Here it is in a single handler and about as concise as I can make it :
$(".nav-right a").click(function() {
var $steps = $(".step"),
index = $steps.filter('.active').removeClass("active").index();
$steps.eq((index + 1) % $steps.length).addClass('active');
});
There's a couple of problems here, but to address the question you could simplify your code to just this and remove the dependency on .step1, .step2, etc in case you decide to add more steps.
$('.nav-right').find('a').on('click', function(e) {
e.preventDefault();
var $activeStep = $('.step.active'),
$expectedNextStep = $activeStep.closest('a').next().find('.step'),
$nextActiveStep = $expectedNextStep.length ? $expectedNextStep : $('.step').first();
$activeStep.removeClass('active');
$nextActiveStep.addClass('active');
});
​
However; I would highly recommend putting this in an ordered list, and not wrapping block elements in an anchor. The page will work as you have it but it's just poor semantics.

Categories

Resources