Need to disable anchor scroll in AJAX code - javascript

https://jsfiddle.net/JTBennett/ekc6yobw/
Here's my current jQuery code:
var rel = "";
var menuUp = true;
$('.navButton').click(function () {
rel = $(this).attr('rel');
menuUp = false;
window.location.hash = rel;
$('#mainContainer').scrollTop(0);
});
$('.resetButton').click(function () {
window.location.hash = "";
menuUp = true;
});
function navigate() {
$('#mainMenu').animate({
opacity: 0,
left: '100%'
}, function () {
$(rel).animate({
top: '0px'
});
});
};
function resetNav() {
$(rel).animate({
top: '110%'
}, function () {
$('#mainMenu').animate({
opacity: 1,
left: '0px'
});
});
};
window.onhashchange = function () {
if (menuUp) {
resetNav();
} else {
navigate();
}
};
I'm attempting to disable the scrolling up to the top of the page on click. I've never done any manipulation of hashes until now...figured I'd better jump on the AJAX bandwagon.
Anyway, I've tried quite a few methods without success (links below).
The most hopeful candidate was this piece of code:
var elems = document.getElementsByClassName('mainContainer');
for (var i=0; i<elems.length; ++i) {
//add click function to each element
elems[i].addEventListener('click', clickFunc);
}
var keepScroll = false;
function clickFunc(e) {
e.preventDefault();
history.replaceState({}, '', e.target.href);
}
I placed it as a separate header script, got no relief. I'm sure the issue is related to the AJAX code relying on the hashes for commands, but I don't know why I can't disable the default action still. If anyone can fork my jsfiddle and find what's wrong, I'd greatly appreciate it.
-Joel
[1]: http://stackoverflow.com/questions/3659072/how-to-disable-anchor-jump-when-loading-a-page
[2]: http://stackoverflow.com/questions/10626814/avoid-the-page-scrolling-jumping-when-anchor-is-in-the-url
[3]: http://jsbin.com/IKoRiTeS/2/edit?html,css,js,output

Related

jquery .hover() with else if statement

I want to put a little delay for onmouseout event for a group of sub items in a drop down menu. But I don't want to use css transitions.
I set it with .hover() and setTimeout method but I wanted to put it only for a specific elements in menu - in this case just for sub items so I used if else statement for them. I have no idea why this if else statement does't work.
Here is my javascript code:
var selectors =
{
element: '.main-menu li:has(ul)'
}
var opacityWorkaround = function ($element, value) {
$element.css('opacity', value);
};
var getAnimationValues = function (visible) {
var result = {
visibility: visible
};
result.opacity = visible === 'visible' ? 1 : 0;
};
var mouseActionHandler = function ($element, visible, opacityValue) {
$element
.stop()
.css("visibility", 'visible')
.animate(getAnimationValues(visible),
3000,
function () {
$(this).css("visibility", visible);
opacityWorkaround($(this), opacityValue);
});
};
var onMouseIn = function () {
var $submenu = $(this).children("ul:first");
if ($submenu) {
mouseActionHandler($submenu, 'visible', 1);
}
};
var onMouseOut = function () {
var $submenu = $(this).children("ul:first");
var $global = $('.global').children('ul');
if ($submenu) {
mouseActionHandler($submenu, 'hidden', 0);
} else if ($global) {
setTimeout(function() {
mouseActionHandler($global, 'hidden', 0);
},1500);
}
};
$(selectors.element).hover(onMouseIn, onMouseOut);
I put 1500ms delay and the $global variable is referring to sub items in menu that I want to make disapear with that delay. I wanted to achieve this when user move mouse cursor out of 'some items >' tab.
Here is my fiddle example.
http://jsfiddle.net/PNz9F/1/
Thanks in advance for any help!
In the example you have in your question $submenu always has a value so the else if statement is never run. You can check for a class instead.
var timeout;
var $submenu = $(this).children("ul:first");
var $global = $('.global').children('ul');
if ($(this).hasClass('menu-item')) {
mouseActionHandler($submenu, 'hidden', 0);
mouseActionHandler($global, 'hidden', 0);
clearTimeout(timeout);
} else if ($(this).hasClass('global')) {
timeout = setTimeout(function() {
mouseActionHandler($global, 'hidden', 0);
},1500);
}
you should be able to just use the :hover selector in your code to check whether the user is hovering over the element or not and run code accordingly

How to stop click events from queuing up on multiple click?

What I need to achieve is if we click on submit button, there is particular div should show up.
Here is my code:
http://jsfiddle.net/7tn5d/
But if I click on submit button multiple times, the function calls sort of queue up and run one after other.
Is there a way to invalidate other onclicks when current animation is running?
Code:
animating = 0;
doneanim = 0;
$(function () {
$("#submit_tab").click(function (e) {
if (animating == 1) return;
animating = 1;
$("#submit_cont").show("blind", {}, 1000);
animating = 0;
});
});
To prevent it from performing the action multiple times, simple cease the previous animation. So:
$('#submit_cont').stop().show("blind",{},1000);
However, I have noticed that you have attempted to prevent the animation from running, if an animation is already running. Although it takes 1 second or 1000 milliseconds to show the div, the execution of the condition does not pause until the animation is complete. You must define a function to run after the animation is complete, like so:
animating = 0;
doneanim = 0;
$(function () {
$("#submit_tab").click(function (e) {
if (animating == 1) return;
animating = 1;
$("#submit_cont").show("blind", 1000, function() { animation = 0; });
});
});
Hope that helped...
You almost got it right with the semaphore! It's just that, in jQuery's show(), you would have to put the semaphore reset as an argument. Here's the fixed version - http://jsfiddle.net/snikrs/xe5A3/
animating = 0;
doneanim = 0;
$(function () {
$("#submit_tab").click(function (e) {
if (animating == 1) return;
animating = 1;
$("#submit_cont").show("blind", 1000, function() {
animating = 0;
});
});
});
You can use the :animated selector to check:
$(function () {
$("#submit_tab").click(function (e) {
var $cont = $("#submit_cont");
if (!$cont.is(':animated')) {
$cont.show("blind", {}, 1000);
}
});
});
Now if you stick with the external semaphore idea then its better to stick that on the elemnt with .data() instead of using a global variable:
$(function () {
$("#submit_tab").click(function (e) {
var $cont = $('#submit_cont'),
animating = $cont.data('isAnimating');
if (animating) {
return;
} else {
$cont.data('isAnimating', 1);
$("#submit_cont").show("blind", 1000, function() { $cont.data('isAnimating', 0); });
}
});
});
Something like this (see documentation) :)
$("#submit_cont").show("blind", function(){
animating = 0;
});
You can add a $("#submit_cont").clearQueue(); after the animation finished :
$("#submit_tab").click(function (e) {
$("#submit_cont").show("blind", 1000, function() {
$("#submit_cont").clearQueue();
});
});
Updated JSFiddle
I found a different solution for this, which in my opinion looks cleaner:
var tab = $("submit_tag");
tab.on("click", function(){
var cont = $("submit_cont");
var animating = tab.queue("fx").length;
if(animating === 0){
cont.show("blind", {}, 1000);
}
});

How to suppress JavaScript function with eg. hasClass?

I'm building on a WordPress theme and wants to load posts and pages with AJAX. I got that sorted out through the snippet below, but now I just need to suppress the function when clicking on the logo, obviously linking to the home url. So when clicking on the logo it should force a normal reload, instead of using the function.
I figure it would have something to do with "if hasClass(logo) then use default"... Yeah, I'm fairly new to JavaScript, but I have been searching a lot, so any help in the right direction will be much appreciated. Thanks!
The snippet:
$(".home li.home").removeClass("home").addClass("current_page_item");
var $wrapperAjax = $("#wrapper-ajax"),
URL = '',
siteURL = "http://" + top.location.host.toString(),
$internalLinks = $("a[href^='"+siteURL+"']"),
hash = window.location.hash,
$ajaxSpinner = $("#ajax-loader"),
$el, $allLinks = $("a");
function hashizeLinks() {
$("a[href^='"+siteURL+"']").each(function() {
$el = $(this);
if ($.browser.msie) {
$el.attr("href", "#/" + this.pathname)
.attr("rel", "internal");
} else {
$el.attr("href", "#" + this.pathname)
.attr("rel", "internal");
}
});
};
hashizeLinks();
$("a[rel='internal']").live("click", function() {
$ajaxSpinner.fadeIn();
$wrapperAjax.animate({ opacity: "0.1" });
$el = $(this);
$(".current_page_item").removeClass("current_page_item");
$allLinks.removeClass("current_link");
URL = $el.attr("href").substring(1);
URL = URL + " .entry";
$wrapperAjax.load(URL, function() {
$el.addClass("current_link").parent().addClass("current_page_item");
$ajaxSpinner.fadeOut();
$wrapperAjax.animate({ opacity: "1" });
hashizeLinks();
});
});
$("#searchform").submit(function(e) {
$ajaxSpinner.fadeIn();
$wrapperAjax.animate({ opacity: "0.1" });
$el = $(this);
$(".current_page_item").removeClass("current_page_item");
$allLinks.removeClass("current_link");
URL = "/?s=" + $("#s").val() + " .entry";
$wrapperAjax.load(URL, function() {
$ajaxSpinner.fadeOut();
$wrapperAjax.animate({ opacity: "1" });
hashizeLinks();
});
e.preventDefault();
});
if ((hash) && (hash != "#/")) {
$("a[href*='"+hash+"']").trigger("click");
}
I'm guessing you mean the script from this line: $("a[rel='internal']")
In that case, $("a[rel='internal']").not('.logo') should do the trick.
I should've read the entire code. Replace $("a[href^='"+siteURL+"']") with $("a[href^='"+siteURL+"']").not('.logo') as well.
If it has the class .logo you could add this at the top of the function:
if ($(this).hasClass('logo')) return true;
See the simple example.

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

setInterval with other jQuery events - Too many recursions

I'm trying to build a Javascript listener for a small page that uses AJAX to load content based on the anchor in the URL. Looking online, I found and modified a script that uses setInterval() to do this and so far it works fine. However, I have other jQuery elements in the $(document).ready() for special effects for the menus and content. If I use setInterval() no other jQuery effects work. I finagled a way to get it work by including the jQuery effects in the loop for setInterval() like so:
$(document).ready(function() {
var pageScripts = function() {
pageEffects();
pageURL();
}
window.setInterval(pageScripts, 500);
});
var currentAnchor = null;
function pageEffects() {
// Popup Menus
$(".bannerMenu").hover(function() {
$(this).find("ul.bannerSubmenu").slideDown(300).show;
}, function() {
$(this).find("ul.bannerSubmenu").slideUp(400);
});
$(".panel").hover(function() {
$(this).find(".panelContent").fadeIn(200);
}, function() {
$(this).find(".panelContent").fadeOut(300);
});
// REL Links Control
$("a[rel='_blank']").click(function() {
this.target = "_blank";
});
$("a[rel='share']").click(function(event) {
var share_url = $(this).attr("href");
window.open(share_url, "Share", "width=768, height=450");
event.preventDefault();
});
}
function pageURL() {
if (currentAnchor != document.location.hash) {
currentAnchor = document.location.hash;
if (!currentAnchor) {
query = "section=home";
} else {
var splits = currentAnchor.substring(1).split("&");
var section = splits[0];
delete splits[0];
var params = splits.join("&");
var query = "section=" + section + params;
}
$.get("loader.php", query, function(data) {
$("#load").fadeIn("fast");
$("#content").fadeOut(100).html(data).fadeIn(500);
$("#load").fadeOut("fast");
});
}
}
This works fine for a while but after a few minutes of the page being loaded, it drags to a near stop in IE and Firefox. I checked the FF Error Console and it comes back with an error "Too many Recursions." Chrome seems to not care and the page continues to run more or less normally despite the amount of time it's been open.
It would seem to me that the pageEffects() call is causing the issue with the recursion, however, any attempts to move it out of the loop breaks them and they cease to work as soon as setInterval makes it first loop.
Any help on this would be greatly appreciated!
I am guessing that the pageEffects need added to the pageURL content.
At the very least this should be more efficient and prevent duplicate handlers
$(document).ready(function() {
pageEffects($('body'));
(function(){
pageURL();
window.setTimeout(arguments.callee, 500);
})();
});
var currentAnchor = null;
function pageEffects(parent) {
// Popup Menus
parent.find(".bannerMenu").each(function() {
$(this).unbind('mouseenter mouseleave');
var proxy = {
subMenu: $(this).find("ul.bannerSubmenu"),
handlerIn: function() {
this.subMenu.slideDown(300).show();
},
handlerOut: function() {
this.subMenu.slideUp(400).hide();
}
};
$(this).hover(proxy.handlerIn, proxy.handlerOut);
});
parent.find(".panel").each(function() {
$(this).unbind('mouseenter mouseleave');
var proxy = {
content: panel.find(".panelContent"),
handlerIn: function() {
this.content.fadeIn(200).show();
},
handlerOut: function() {
this.content.slideUp(400).hide();
}
};
$(this).hover(proxy.handlerIn, proxy.handlerOut);
});
// REL Links Control
parent.find("a[rel='_blank']").each(function() {
$(this).target = "_blank";
});
parent.find("a[rel='share']").click(function(event) {
var share_url = $(this).attr("href");
window.open(share_url, "Share", "width=768, height=450");
event.preventDefault();
});
}
function pageURL() {
if (currentAnchor != document.location.hash) {
currentAnchor = document.location.hash;
if (!currentAnchor) {
query = "section=home";
} else {
var splits = currentAnchor.substring(1).split("&");
var section = splits[0];
delete splits[0];
var params = splits.join("&");
var query = "section=" + section + params;
}
var content = $("#content");
$.get("loader.php", query, function(data) {
$("#load").fadeIn("fast");
content.fadeOut(100).html(data).fadeIn(500);
$("#load").fadeOut("fast");
});
pageEffects(content);
}
}
Thanks for the suggestions. I tried a few of them and they still did not lead to the desirable effects. After some cautious testing, I found out what was happening. With jQuery (and presumably Javascript as a whole), whenever an AJAX callback is made, the elements brought in through the callback are not binded to what was originally binded in the document, they must be rebinded. You can either do this by recalling all the jQuery events on a successful callback or by using the .live() event in jQuery's library. I opted for .live() and it works like a charm now and no more recursive errors :D.
$(document).ready(function() {
// Popup Menus
$(".bannerMenu").live("hover", function(event) {
if (event.type == "mouseover") {
$(this).find("ul.bannerSubmenu").slideDown(300);
} else {
$(this).find("ul.bannerSubmenu").slideUp(400);
}
});
// Rollover Content
$(".panel").live("hover", function(event) {
if (event.type == "mouseover") {
$(this).find(".panelContent").fadeIn(200);
} else {
$(this).find(".panelContent").fadeOut(300);
}
});
// HREF Events
$("a[rel='_blank']").live("click", function(event) {
var target = $(this).attr("href");
window.open(target, "_blank");
event.preventDefault();
});
$("a[rel='share']").live("click", function(event) {
var share_url = $(this).attr("href");
window.open(share_url, "Share", "width=768, height=450");
event.preventDefault();
});
setInterval("checkAnchor()", 500);
});
var currentAnchor = null;
function checkAnchor() {
if (currentAnchor != document.location.hash) {
currentAnchor = document.location.hash;
if (!currentAnchor) {
query = "section=home";
} else {
var splits = currentAnchor.substring(1).split("&");
var section = splits[0];
delete splits[0];
var params = splits.join("&");
var query = "section=" + section + params;
}
$.get("loader.php", query, function(data) {
$("#load").fadeIn(200);
$("#content").fadeOut(200).html(data).fadeIn(200);
$("#load").fadeOut(200);
});
}
}
Anywho, the page works as intended even in IE (which I rarely check for compatibility). Hopefully, some other newb will learn from my mistakes :p.

Categories