Jquery click firing on all elements - javascript

I am attempting to use Bootstrap's Collapse feature with custom icons from font-awesome. I am able to get the collapse to work but the problem I am having is that all of the icons are being triggered with Jquery's click, I want to scale this because at any given time the amount of "containers" can change. Any suggestions are appreciated.
$(document).ready(function () {
$faChevronDown = $('.fa-chevron-down');
var z = 0;
$faChevronDown.click(function () {
if (z == 0) {
turnUp();
z++;
} else {
turnDown();
z = 0;
}
});
});
function turnUp() {
$faChevronDown.removeClass('fa-chevron-down');
$faChevronDown.addClass('fa-chevron-up');
};
function turnDown() {
$faChevronDown.removeClass('fa-chevron-up');
$faChevronDown.addClass('fa-chevron-down');
};
JS Fiddle
Thank you
Edit : Thank you for the great answers!

You are clicking only one element, but your function is changing all icons, you have use $(this) instead in order to only change the icon you are clicking:
function toggleClass() {
$(this).toggleClass('fa-chevron-down fa-chevron-up');
};
and then use only one function:
$faChevronDown.click(toggleClass);
With this you avoid the use of Ifs and elses and the code is much simplier and small.

Set click handler on the parent element of a .fa-chevron-down element or if the parent element is not known on body element:
$(document).ready(function () {
var z = 0;
$("body").on("click", ".fa-chevron-down", function () {
if (z == 0) {
turnUp.call(this);
z++;
} else {
turnDown.call(this);
z = 0;
}
});
});
function turnUp() {
$(this).removeClass('fa-chevron-down');
$(this).addClass('fa-chevron-up');
};
function turnDown() {
$(this).removeClass('fa-chevron-up');
$(this).addClass('fa-chevron-down');
};
If you are using z variable only for switching classes fa-chevron-down and fa-chevron-up, the code could be simplified to:
$(document).ready(function () {
$("body").on("click", ".fa-chevron-down", function () {
$(this).toggleClass('fa-chevron-down fa-chevron-up');
});
});

You can pass in the element to perform granular toggling,
$(document).ready(function () {
$fa= $('.fa');
var z = 0;
$fa.click(function () {
if (z == 0) {
turnUp($(this));
z++;
} else {
turnDown($(this));
z = 0;
}
});
});
function turnUp(el) {
el.removeClass('fa-chevron-down');
el.addClass('fa-chevron-up');
};
function turnDown(el) {
el.removeClass('fa-chevron-up');
el.addClass('fa-chevron-down');
};

I'm not sure what the point of your z variable is, but you can reduce what you have, and fix the problem of not referencing the element by using this, by using just:
$(document).ready(function () {
$('.fa-chevron-down').click(function () {
$(this).toggleClass('fa-chevron-down fa-chevron-up')
});
});
jsFiddle example

Related

jQuery: index slice function in iterations

I have a slice function set up, calling the index of a .test to fade in the .test divs in blocks of 5. There's a demo here: http://jsfiddle.net/neal_fletcher/JT4KB/2/
jQuery:
$(document).ready(function () {
$('.test').each(function (index) {
$('.test').slice(0, 5).delay(500).fadeIn(300);
$('.test').slice(5, 10).delay(1000).fadeIn(300);
$('.test').slice(10, 15).delay(1500).fadeIn(300);
});
});
This works fine, but as the site will be content managed I want a more compact solution, thus instead of having to write a function for every 5 divs, is there a way to call this function by adding an extra 500 onto the delay for every 5 divs? If that makes sense? Any suggestions would be greatly appreciated!
Here you go sir.
http://jsfiddle.net/JT4KB/17/
$(document).ready(function () {
setTimeout(function () {
$('.test').each(function (i) {
var delay = Math.floor(i/5)*500 + 500;
$(this).delay(delay).fadeIn(300);
});
}, 1000);
});
You can use a loop to achieve this. This loop has to loop 'the number of .test divs'/5 times:
$(document).ready(function () {
setTimeout(function () {
for (i=0; i<=$('.test').length/5; i++) {
$('.test').slice(5 * i, 5*(i+1)).delay(500*(i+1)).fadeIn(300);
};
}, 1000);
});
You can add a new method to jQuery like this:
$.fn.eachSlice = function(size, callback) {
var $t = $(this);
for(var i = 0; i < $t.length; i += size) {
callback.call($t.slice(i, i + size).get(), i / size);
}
return $t;
}
and then
$(".test").eachSlice(5, function(sliceIndex) {
$(this).delay(sliceIndex * 500).fadeIn();
});
http://jsfiddle.net/JT4KB/16/

Starting and ending functions in javascript

I am playing around with a short little code to see if I can get a function going while the user has their mouse down and then end it when they bring their mouse up. For this example I am trying to increment a number that I am displaying on the screen as the user moves their mouse while holding the button down. I want it to freeze and stop once they release the button, however the counter just resets and the count continues from 0 even though the button is not being pressed...
function dragInit(state, e) {
var i = 0;
$(document).on("mousemove", function() {
if (state) {
i+=1;
$('#debug').text(i); //Show the value in a div
}
});
}
$(document).ready(function() {
$(document).on(
{mousedown: function(e) {
var state = true;
dragInit(e, state);
},
mouseup: function(e) {
var state = false;
dragInit(e, state);
}
});
});
As an aside, is there a way I can display whether a variable is true or false onscreen? When I try it just says [object Object].
There are a lot of mistakes in your code. I suggest you to read more basic concepts before starting to use jQuery.
The order of the parameters passed to dragInit() is wrong on both mouseup and mousedown event bindings.
The reason your counter is restarting is because your variable i is local, so it exists only during the function context it is declared in.
You are making the same mistake with the state variable, but in this case it is completely unnecessary to declare it.
Consider making your counter a global (even though it is not a good practice).
I can't provide you code because I am answering from my phone. A solution would be create a mousemove event that checkes whether the mouse button is pressed before incrementing your counter.
Hope I helped
You could do something like this:
function dragInit() {
$(document).on("mousemove", function () {
if (eventState.state) {
eventState.count += 1;
$('#debug').text(eventState.count); //Show the value in a div
}
});
}
// Create an object to track event variables
var eventState = {
count:0, //replaces your previous 'i' variable
state: false //keeps track of mouseup or mousedown
};
$(document).ready(function () {
$(document).on({
mousedown: function (e) {
eventState.state = true;
dragInit(); //don't need to pass anything anymore
},
mouseup: function (e) {
eventState.state = false;
dragInit(); //don't need to pass anything anymore
}
});
});
jsFiddle
Or keep everything together as one object
var dragInit = function () {
var count = 0;
var state = false;
var action = function () {
$(document).on("mousemove", function () {
if (state) {
count += 1;
$('#debug').text(count); //Show the value in a div
}
})
};
$(document).on({
mousedown: function (e) {
state = true;
action(); //don't need to pass anything anymore
},
mouseup: function (e) {
state = false;
action(); //don't need to pass anything anymore
}
});
}
$(document).ready(function () {
var obj = new dragInit();
});
jsFiddle 2
Example in response to comment
jsFiddle: This shows why the following code snippets differ in execution.
// Works
$(document).on("mousemove", function () {
if (state) {
}
})
// Doesn't
if (state) {
$(document).on("mousemove", function () {
});
}
Less code, You just need this.
Use jquery on and Off to turn on and off mousemove event.
Counter Reset http://jsfiddle.net/kRtEk/
$(document).ready(function () {
var i = 0;
$(document).on({
mousedown: function (e) {
$(document).on("mousemove", function () {
$('#debug').text(i++); //Show the value in a div
});
},
mouseup: function (e) {
i = 0;
$('#debug').text(i);
$(document).off("mousemove");
}
});
});
W/O Reset http://jsfiddle.net/gumwj/
$(document).ready(function () {
var i = 0;
$(document).on({
mousedown: function (e) {
$(document).on("mousemove", function () {
$('#debug').text(i++); //Show the value in a div
});
},
mouseup: function (e) {
$(document).off("mousemove");
}
});
});
WithNoCounter http://jsfiddle.net/F3ESx/
$(document).ready(function () {
$(document).on({
mousedown: function (e) {
$(document).on("mousemove", function () {
$('#debug').data('idx',parseInt($('#debug').data('idx')|0)+1).text($('#debug').data('idx')); //Show the value in a div
});
},
mouseup: function (e) {
$(document).off("mousemove");
}
});
});
Assuming you are married to Jquery (nothing wrong with that) - check out and consider entirely re-thinking your approach leveraging the ".one()" (http://api.jquery.com/one/) method.
edit: and if that taste doesn't sit well - familiarize yourself with the "deferred" object (http://api.jquery.com/category/deferred-object/)
lots of ways to approach this via jquery - what you decide in the end depends on what you really intend to do with this.

How to click a Button with specific text?

I am trying to modify the script below to click a button that looks like this on a site:
<button id="checkPrice-02070" onclick="checkPrice(02070,null); return false;" class="orangeDark">
<span>check price</span>
</button>
I am using the code below. So far, the page seems to keep reloading; nothing else happens.
Any advice to someone new?
(function () {
window.addEventListener("load", function (e) {
clickConfirmButton()
}, false);
})();
function clickConfirmButton() {
var buttons = document.getElementsByTagName('button');
var clicked = false;
for (var index = 0; (index < buttons.length); index++) {
if (buttons[index].value == "check price") {
buttons[index].click();
clicked = true;
break;
}
}
if (!clicked) {
setTimeout("window.location.reload()", 300 * 1000);
}
}
A <button>s value is not the visible text. You'd want to search textContent.
However:
If that sample HTML is correct, you'd be better off searching for ids that start with checkPrice. See the code below.
Are you sure you want to reload if the button is not found? If it is added by AJAX this is not the best approach. See this answer.
Don't use setTimeout with a string (to evaluate) argument like that. See the code below.
You do not need to wrap the code in an anonymous function.
Anyway, this should work, given the sample HTML:
window.addEventListener ("load", clickConfirmButton, false);
function clickConfirmButton (zEvent) {
var button = document.querySelector ("button[id^='checkPrice']");
if (button) {
button.click ();
}
else {
setTimeout (function () { location.reload(); }, 300 * 1000);
}
}
To check the button text anyway, use:
function clickConfirmButton (zEvent) {
var buttons = document.querySelectorAll ("button[id^='checkPrice']");
var clicked = false;
for (var index = 0, numBtn = buttons.length; index < numBtn; ++index) {
if (/check price/i.test (buttons[index].textContent) ) {
buttons[index].click();
clicked = true;
break;
}
}
if (!clicked) {
setTimeout (function () { location.reload(); }, 300 * 1000);
}
}

Converting javascript functions to jQuery

I have some javascript which I want to convert to jQuery...
I thought it would be easy, but it would appear I was wrong!
The code should resize a textarea depending on the amount of text entered into it.
Here's my code:
function haut() {
if ($(this).scrollTop() > 0) aug();
}
function aug() {
var h = parseInt($(this).height());
$(this).height(h + 10);
haut();
}
function top() {
$(this).scrollTop(100000);
haut();
}
$(document).ready( function() {
$("#txt_test").keyup(function() {
haut();
});
$("#txt_test").focus(function() {
top();
});
});
And here's the original code:
function haut(idt) {
if (document.getElementById(idt).scrollTop > 0) aug(idt);
}
function aug(idt) {
var h = parseInt(document.getElementById(idt).style.height);
document.getElementById(idt).style.height = h + 10 +"px";
haut(idt);
}
function top(idt) {
document.getElementById(idt).scrollTop = 100000;
haut(idt);
}
$(document).ready( function() {
$("#txt_test").keyup(function() {
haut(this.id);
});
$("#txt_test").focus(function() {
top(this.id);
});
});
Here's a jsfiddle if it helps... http://jsfiddle.net/HhRUH/
Please describe your problems specifically when you're asking a question.
So far I see you have the wrong code for binding handlers. It should be:
$(document).ready( function() {
$("#txt_test").keyup(haut);
$("#txt_test").focus(top);
});
The reason you can use $(this) in keyup(function() { ... }); is because of how it was called by the jQuery implementation. See javascript's .call and .apply for more information about setting context (this) manually.
In your code, you're not using haut.call(), but haut(), which will not set the this context. Therefore this means something different in haut when it's invoked like $('*').keyup(haut) than when it is invoked like $('*').keyup(function() { haut(); });. The same goes for your calling aug() from haut.
just send parameter to aug
function haut(idt) {
if ($(this).scrollTop() > 0) aug(idt);
}
http://jsfiddle.net/HhRUH/1/
You're using this wrong. Pass the element instead:
function haut(element) {
if (element.scrollTop() > 0) aug(element);
}
function aug(element) {
var h = parseInt(element.height());
element.height(h + 10);
haut(element);
}
function top(element) {
element.scrollTop(100000);
haut(element);
}
$(document).ready(function() {
$("#txt_test").keyup(function() {
haut($(this));
});
$("#txt_test").focus(function() {
top($(this));
});
});
You are losing scope. You can use:
1) dmitry's answer(and I think the best one)
$("#txt_test").keyup(haut);
$("#txt_test").focus(top);
2) or if you want to do some more things in the callback, you can do it
with using call():
$("#txt_test").keyup(function()
{
haut.call(this);
alert('...');
});
$("#txt_test").focus(function()
{
top.call(this);
});

Javascript "while hovered" loop

Can anybody help me on this one...I have a button which when is hovered, triggers an action. But I'd like it to repeat it for as long as the button is hovered.
I'd appreciate any solution, be it in jquery or pure javascript - here is how my code looks at this moment (in jquery):
var scrollingposition = 0;
$('#button').hover(function(){
++scrollingposition;
$('#object').css("right", scrollingposition);
});
Now how can i put this into some kind of while loop, so that #object is moving px by px for as #button is hovered, not just when the mouse enters it?
OK... another stab at the answer:
$('myselector').each(function () {
var hovered = false;
var loop = window.setInterval(function () {
if (hovered) {
// ...
}
}, 250);
$(this).hover(
function () {
hovered = true;
},
function () {
hovered = false;
}
);
});
The 250 means the task repeats every quarter of a second. You can decrease this number to make it faster or increase it to make it slower.
Nathan's answer is a good start, but you should also use window.clearInterval when the mouse leaves the element (mouseleave event) to cancel the repeated action which was set up using setInterval(), because this way the "loop" is running only when the mouse pointer enters the element (mouseover event).
Here is a sample code:
function doSomethingRepeatedly(){
// do this repeatedly when hovering the element
}
var intervalId;
$(document).ready(function () {
$('#myelement').hover(function () {
var intervalDelay = 10;
// call doSomethingRepeatedly() function repeatedly with 10ms delay between the function calls
intervalId = setInterval(doSomethingRepeatedly, intervalDelay);
}, function () {
// cancel calling doSomethingRepeatedly() function repeatedly
clearInterval(intervalId);
});
});
I created a sample code on jsFiddle which demonstrates how to scroll the background-image of an element left-to-right and then backwards on hover with the code shown above:
http://jsfiddle.net/Sk8erPeter/HLT3J/15/
If its an animation you can "stop" an animation half way through. So it looks like you're moving something to the left so you could do:
var maxScroll = 9999;
$('#button').hover(
function(){ $('#object').animate({ "right":maxScroll+"px" }, 10000); },
function(){ $('#object').stop(); } );
var buttonHovered = false;
$('#button').hover(function () {
buttonHovered = true;
while (buttonHovered) {
...
}
},
function () {
buttonHovered = false;
});
If you want to do this for multiple objects, it might be better to make it a bit more object oriented than a global variable though.
Edit:
Think the best way of dealing with multiple objects is to put it in an .each() block:
$('myselector').each(function () {
var hovered = false;
$(this).hover(function () {
hovered = true;
while (hovered) {
...
}
},
function () {
hovered = false;
});
});
Edit2:
Or you could do it by adding a class:
$('selector').hover(function () {
$(this).addClass('hovered');
while ($(this).hasClass('hovered')) {
...
}
}, function () {
$(this).removeClass('hovered');
});
var scrollingposition = 0;
$('#button').hover(function(){
var $this = $(this);
var $obj = $("#object");
while ( $this.is(":hover") ) {
scrollingposition += 1;
$obj.css("right", scrollingposition);
}
});

Categories