What does "this" actually refer to in this context? - javascript

I have this simple script (see below) and I expected the div to "bounce". However, it doesn't when I use this.effect("bounce");. It does work when I use the variable that contains the element: $arrow_go_up.effect("shake");
When I console.log the this, it shows me the element, so I am confused.
I tried to use an arrow-function, then this points to the window-element though.
$(document).ready(function() {
var $arrow_go_up = $("#arrow_go_up");
window.onscroll = function() {
if (window.scrollY > 100) {
$arrow_go_up.removeClass("d-none");
} else {
$arrow_go_up.addClass("d-none");
}
}
$arrow_go_up.on("mouseover", function() {
this.effect("bounce", {
times: 1
});
});
});

Related

variable assignment not working

I do not understand why my variable assignment: var mn = $("nav"); is not working in this piece of code:
var mn = $("nav");
var randomNum = 23;
$(window).scroll(function() {
if( $(this).scrollTop() > 400 ) {
$("nav").addClass("main-nav-scroll");
alert(randomNum);
} else {
mn.removeClass("main-nav-scroll");
}
});
When I manually write it out in $("nav").addClass(...); it works perfectly. I thought the problem was maybe the scope of the variable so I added the randomNum variable to print out and it does so just fine. I'm really stumped. It took me forever to find this simple error So I'd like to understand for next time. Thanks.
Your problem is likely nav. It is a dom element just like <p>. So when you try to select it your query is to general.
Give nav and ID and select it that way.
For example
HTML
<nav id "foob"></nav>
JS
var mn = $("#foob");
In Addition
Also, put a console.log('scroll event fired') in your event handler so that you can verify that the event is actually firing.
This works:
<script type="text/javascript">
jQuery(document).ready(function ($selimatac) {
// öncelikle divi bir gizleyelim
$selimatac("#yukari").hide();
//scroll eğer 100 değerinin üstünde ise divi görünür yapacak, değilse gizleyecektir
$selimatac(function () {
$selimatac(window).scroll(function () {
if ($selimatac(this).scrollTop() > 100) {
$selimatac('#yukari').fadeIn();
} else {
$selimatac('#yukari').fadeOut();
}
});
// butona tıklayınca sayfa en üste çıkması için
$selimatac('div a').click(function () {
$selimatac('window,html,body').animate({
scrollTop: 0
}, 1000);
return false;
});
});
});
</script>
Look at http://selimatac.net/jquery-scrolltop-ile-yukari-cik-butonu/ for more information.
Maybe your var gets rewritten somewhere in your code. Try another var name

Jquery click firing on all elements

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

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);
});

Why is my JavaScript for suspending and unsuspending a user not working correctly?

I'm building a site for someone and on the Admin side there is a "Manage Users" page to manage the website's users. Here is my two functions to suspend and unsuspend (and for the alert):
var admin = {
alert: (function(msg,dur) {
if(!dur || dur == null) {
dur = 1500;
}
$('#alert_box2').remove();
$('body').append('<div id="alert_box2" style="width: 100%; height: 9px; top: -17px; left: 0; position: absolute; text-align: center; z-index: 5;"><div id="alert_box_inner2"></div></div>');
$('#alert_box2').show(0, function() {
if(dur!=='none') {
$('#alert_box_inner2').html(msg).stop(true, true).fadeIn(800).delay(dur).fadeOut(800, function() {
$('#alert_box2').remove();
});
}
else {
$('#alert_box_inner').html(msg).show();
}
});
}),
suspendUser: (function(id) {
admin.alert('Please wait...',20000);
$.get('user_more_actions.php?action=suspend&nolightbox=1&id='+id, function(data,textStatus) {
setTimeout(function() {
if(textStatus=='success') {
if(data.indexOf('suspended') > -1) {
name = data.replace('suspended ','');
admin.alert(name+' is now suspended.',2500);
$('#status_'+id).html('<strong style="color: red;">Suspended</strong>');
$('#suspend_'+id).attr('id','unsuspend_'+id).text('Unsuspend').removeClass('suspend').addClass('unsuspend');
}
else {
admin.alert('Sorry, there was an error. <span class="s_link" onclick="$(\'#suspend_'+id+'\').click();">Try again</a>','none');
}
}
else {
admin.alert('Sorry, there was an error. <span class="s_link" onclick="$(\'#suspend_'+id+'\').click();">Try again</a>','none');
}
}, 500);
});
}),
unsuspendUser: (function(id) {
admin.alert('Please wait...',20000);
$.get('user_more_actions.php?action=unsuspend&nolightbox=1&id='+id, function(data,textStatus) {
setTimeout(function() {
if(textStatus=='success') {
if(data.indexOf('unsuspended') > -1) {
name = data.replace('unsuspended ','');
admin.alert(name+' is no longer suspended.',2500);
$('#status_'+id).html('<strong style="color: green;">Active</strong>');
$('#unsuspend_'+id).attr('id','suspend_'+id).text('Suspend').removeClass('unsuspend').addClass('suspend');
}
else {
admin.alert('Sorry, there was an error. <span class="s_link" onclick="$(\'#unsuspend_'+id+'\').click();">Try again</a>',20000);
}
}
else {
admin.alert('Sorry, there was an error. <span class="s_link" onclick="$(\'#unsuspend_'+id+'\').click();">Try again</a>',20000);
}
}, 500);
});
})
};
And the code that triggers the functions when a Suspend or Unsuspend link is clicked:
$('.suspend').each(function() {
$(this).live('click', function(e) {
e.preventDefault();
var id = $(this).attr('id').replace('suspend_', '');
admin.suspendUser(id);
});
});
$('.unsuspend').each(function() {
$(this).live('click', function(e) {
e.preventDefault();
var id = $(this).attr('id').replace('unsuspend_', '');
admin.unsuspendUser(id);
});
});
Everything is working ok, except when I click again it messes up. When a Suspend link is clicked, it changes to Unsuspend (and changes the ID). But then if I click Unsuspend it doesn't work, and it is calling the admin.suspend() function instead of admin.unsuspend() (and the ID isn't being passed so the name isn't displayed):
When the class and the ID is changed it should call either the admin.suspend(id_here) or admin.unsuspend(id_here); but it isn't.
Does anyone know why this is happening? Thanks in advance and I'm sorry that this post is long.
I've fiddled with it. Hope this helps:http://jsfiddle.net/wKGKu/
Update: After reading your concerns for .each, I've updated the code to demonstrate it isn't needed: http://jsfiddle.net/wKGKu/2/
I believe the way you wrote your live bindings is incorrect, they should have been bound like this:
$('.suspend').live('click', function(e) {
e.preventDefault();
var id = $(this).attr('id').replace('suspend_', '');
admin.suspendUser(id);
});
$('.unsuspend').live('click', function(e) {
e.preventDefault();
var id = $(this).attr('id').replace('unsuspend_', '');
admin.unsuspendUser(id);
});
I simplified fiddle showing the working code at: jsFiddle
You are attaching events to suspend/unsuspend classes, but your AJAX callback is modifying id attribute. Also you are horribly misusing live(). In the end your handler is already attached to the link and doesn't change after your AJAX calls.
Solution is to
1) leave ID's alone - you are only confusing yourself by modifying them
2) rewrite event handler to either not do each() or not use live - put together completely defeats purpose behind live()
$('.suspend').live('click', function(){
var id = $(this).attr('id').replace('suspend_', '');
admin.suspendUser(id);
return false;
});
$('.unsuspend').live('click', function(e){
var id = $(this).attr('id').replace('suspend_', '');
admin.unsuspendUser(id);
return false;
});

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