Conflicting scripts, what's the issue? - javascript

I use 2 different scripts on a webpage - one pure JS, the other jQuery.
The JS script is used for toggling the hamburger menu in mobile view. hamb.onclick shows the menu when clicking on hamburger, menuL.onclick hides the menu when clicking on a menu item. The latter refuses to work when the jQuery script is active (it works when the jQuery script is commented out).
<script>
(function () {
function hasClass(elem, className) {
return new RegExp(' ' + className + ' ').test(' ' + elem.className + ' ');
}
function toggleClass(elem, className) {
var newClass = ' ' + elem.className.replace(/[\t\r\n]/g, ' ') + ' ';
if (hasClass(elem, className)) {
while (newClass.indexOf(' ' + className + ' ') >= 0) {
newClass = newClass.replace(' ' + className + ' ', ' ');
}
elem.className = newClass.replace(/^\s+|\s+$/g, '');
} else {
elem.className += ' ' + className;
}
}
var hamb = document.querySelector('.hamburger');
var menuL = document.querySelector('.menuList');
hamb.onclick = function () {
toggleClass(this, 'hamburgerOpen');
toggleClass(menuL, 'menuActive');
};
menuL.onclick = function () {
toggleClass(hamb, 'hamburgerOpen');
toggleClass(menuL, 'menuActive');
};
})();
</script>
The jQuery is used for smooth navigation/scrolling to the anchors of the page:
<script>
function scrollNav() {
$('.menu a').click(function(){
//Toggle Class
$(".active").removeClass("active");
$(this).closest('li').addClass("active");
var theClass = $(this).attr("class");
$('.'+theClass).parent('li').addClass('active');
//Animate
$('html, body').stop().animate({
scrollTop: $( $(this).attr('href') ).offset().top - 160
}, 800);
return false;
});
$('.scrollTop a').scrollTop();
}
scrollNav();
</script>
As i understand it, the jQuery script highjacks the onclick event of the JS script, because they work on the same parent element: ".menu a" and "menuList" (which is the "ul" inside ".menu").
What can i do to get both scripts working together? I'm a beginner and my JavaScript skills are still weak.

If the second script hijacks the event, just move the function into the second script and run it there.
It works!

Related

Jquery to toggle one div of same class on click

function demo(){
$('.box').slideToggle('fast');
}
$(document).ready(function(){
$.getJSON( "js/JobOpenings.json", function( data ) {
var glrScrlImg = [];
$.each( data.getJobOpeningsResult, function( key, val ) {
var st = "",id,st2= "",st3="",id;
st +="<h4>" + val.JobTitle + "</h4>";
st3 += "<div class='box'>" + val.JobDetails + "</div>";
$("#newsDetails").append("<li onclick='demo()'>" + st+val.JobSector + "<br>" + st3 + "</li>");
$('.box').hide();
});
});
});
I am reading data from a json file. The div with 'box' class is hidden. Currently this code is displaying all div on click of the li. What changes should I make to display only the div corresponding to the clicked li?
Here what we need to do is to find the .box element within the clicked li, so we need to get a reference to the clicked element.
I would use a delegated jQuery event handler with css to initially hide the element
$(document).ready(function () {
$('#newsDetails').on('click', 'li', function () {
$(this).find('.box').toggleClass('hidden');
})
$.getJSON("js/JobOpenings.json", function (data) {
var glrScrlImg = [];
$.each(data.getJobOpeningsResult, function (key, val) {
var st = "",
id, st2 = "",
st3 = "",
id;
st += "<h4>" + val.JobTitle + "</h4>";
st3 += "<div class='box hidden'>" + val.JobDetails + "</div>";
$("#newsDetails").append("<li>" + st + val.JobSector + "<br>" + st3 + "</li>");
});
});
});
with css
.hidden {
display: none;
}
Pass the control to the function and then based on your control slideToggle its respective .box
function demo(ctrl){
$(ctrl).find('.box').slideToggle('fast');
}
$(document).ready(function(){
$.getJSON( "js/JobOpenings.json", function( data ) {
var glrScrlImg = [];
$.each( data.getJobOpeningsResult, function( key, val ) {
var st = "",id,st2= "",st3="",id;
st +="<h4>" + val.JobTitle + "</h4>";
st3 += "<div class='box'>" + val.JobDetails + "</div>";
$("#newsDetails").append("<li onclick='demo(this)'>" + st+val.JobSector + "<br>" + st3 + "</li>");
$('.box').hide();
});
});
});
Or add a class to li and attach an event handler like below instead of writing inline onclick as below:
$("#newsDetails").append("<li class="someclass"'>" + st+val.JobSector + "<br>" + st3 + "</li>");
and then instead of function demo() write this
$('#newsDetails').on('click','.someclass',function(){
$(this).find('.box').slideToggle('fast');
});
UPDATE
Method 1:
function demo(ctrl){
$('#newsDetails').find('li.box').hide('fast'); //hide all the .box
$(ctrl).find('.box').slideToggle('fast');
}
Method 2:
$('#newsDetails').on('click','.someclass',function(){
$('#newsDetails').find('li.box').hide('fast'); //hide all the .box
$(this).find('.box').slideToggle('fast');
});
UPDATE 2:
Method 1:
function demo(ctrl){
$('#newsDetails').find('li.box').not($(ctrl).find('.box')).hide('fast'); //hide all the .box
$(ctrl).find('.box').slideToggle('fast');
}
Method 2:
$('#newsDetails').on('click','.someclass',function(){
$('#newsDetails').find('li.box').not($(ctrl).find('.box')).hide('fast'); //hide all the .box except this
$(this).find('.box').slideToggle('fast');
});
You should structure your html (which is missing from the question!) so that the div and li are "connected" in some way (maybe the div is child of li, or they have same class, ecc).
Right now the line
$('.box').slideToggle('fast');
is applied to all element with class '.box' in your page. You want to be more selective there, that's where the way you structure the html comes into play.
Here's an example: http://jsfiddle.net/owe0faLs/1/

jQuery click fires twice

I have this jsfiddle: http://jsfiddle.net/us28bg4u/1/
How come, that, when I press "First" -> "Left" the action is only fired once. But when I do it again, the action is fired twice, and third time I press the same, it fires three times and so on.
I cant figure out why it is stacking up. Can someone enlighten me? :)
I have tried with:
e.stopPropagation();
e.preventDefault();
- but nothing seems to prevent the clicks for stacking up.
my js looks like this:
var side = '';
var action = '';
$(document).ready(function () {
$(".first").click(function (e) {
logit("First pressed");
preStart('first');
});
$(".second").click(function (e) {
logit('Second pressed');
preStart('second');
});
function preStart(action) {
$("#overlay").fadeIn(200);
$(".leftside").click(function (e) {
side = "left";
$("#overlay").fadeOut(200);
logit('Starting ' + action + ' (' + side + ')');
});
$(".rightside").click(function (e) {
side = "right";
$("#overlay").fadeOut(200);
logit('Starting ' + action + ' (' + side + ')');
});
}
function logit(logtxt){
$("#log").append("<li>"+logtxt+"</li>");
}
});
Has it something to do with the click() functions being in another function?
Event bindings can stack. Inside of preStart clear the previous binding by adding .unbind() into the method chain before the event is bound again like so:
function preStart(action) {
$("#overlay").fadeIn(200);
$(".leftside").unbind("click").click(function (e) {
side = "left";
$("#overlay").fadeOut(200);
logit('Starting ' + action + ' (' + side + ')');
});
$(".rightside").unbind("click").click(function (e) {
side = "right";
$("#overlay").fadeOut(200);
logit('Starting ' + action + ' (' + side + ')');
});
}
You are binding handlers to the events inside the click handler that's why it's happening,
Do it like bellow
var side = '';
var action = '';
$(document).ready(function () {
$(".first").click(function (e) {
logit("First pressed");
preStart('first');
});
$(".second").click(function (e) {
logit('Second pressed');
preStart('second');
});
$(".leftside").click(function (e) {
side = "left";
$("#overlay").fadeOut(200);
logit('Starting ' + action + ' (' + side + ')');
});
$(".rightside").click(function (e) {
side = "right";
$("#overlay").fadeOut(200);
logit('Starting ' + action + ' (' + side + ')');
});
function preStart(action) {
$("#overlay").fadeIn(200);
}
function logit(logtxt){
$("#log").append("<li>"+logtxt+"</li>");
}
});
FIXED DEMO
Handle the click event with OWN parameter Like this. Try this one,
$(".leftside").click(function (e) {
if(!e.handled){
e.handled = true;
side = "left";
$("#overlay").fadeOut(200);
logit('Starting ' + action + ' (' + side + ')');
}
});
$(".rightside").click(function (e) {
if(!e.handled){
e.handled = true;
side = "right";
$("#overlay").fadeOut(200);
logit('Starting ' + action + ' (' + side + ')');
}
});
Update Fiddle
It depends how many times you invoke preStart, when you click first you bind
$(".leftside").click() $(".rightside").click() once, as you click through first or second one more time you created another binding on $(".leftside") and $(".rightside"), so on so forth.
You can always unbind it before you bind it again.
$(".leftside").unbind('click').click(function (e) {
// your code
}
Fiddle

jQuery Submenu delay on mouseOut

I have been working on adding a delay to a submenu I inherited for a major project. After about 10 hours of trying and failing, I could really use some help. I know that there are literally hundreds of examples out there for adding a delay on a submenu using jQuery or even Javascript, but I have not seen one that works in this modular code structure, and I have searched everywhere for a similar example.
I want to try and do this without a major module re-write, as this is a responsive website and I am unsure if changing the way the module works will have a negative impact on functionality.
Here is the code below, which is just one function in a series of UI functions:
MLS.ui = { ...
tabs: function (element, hover) {
var scope = element,
$contentTabs = $jQ(scope + ' > .tab-content > .tab'),
activeClass = 'active';
$jQ(scope + ' > .tab-menu > .tab').each(function (i, el) {
$jQ(this).add($contentTabs[i]).attr('tab', i + 1);
});
$jQ(scope + ' > .tab-menu > .tab').on((hover ? 'mouseenter' : 'click'), function (e) {
if (!hover) {
e.preventDefault();
}
var tab = $jQ(this).attr('tab');
$jQ(scope + ' > .tab-menu > .tab').add(scope + ' > .tab-content > .tab').removeClass(activeClass);
$jQ(this).add(scope + ' > .tab-content > .tab[tab=' + tab + ']').addClass(activeClass);
});
$jQ(scope + ' > .tab-menu > .tab:first-child').add(scope + ' > .tab-content > .tab:first-child').addClass(activeClass);
},
...}
As far as I can tell, the .on event handler is both adding the class 'active', and removing it from the element no longer hovered over, but I do not understand how that is possible.
A few things I have tried are adding a setTimeout around the entire tabs function, setting up a delay and queue on the .on event handler, and even writing a separate module, none of which had any effect (or the incorrect effect, such as firing the removeClass event even if I was still hovered on the element.)
What am I missing here? I cannot afford to waste any more time on this problem.
EDIT:
Here is an example of something I tried, but it just adds the class to every matching DOM element on hover of one li. How can I just target the single hovered element to have the delay to remove the active class?
tabs: function (element, hover) {
var scope = element,
$contentTabs = $jQ(scope + ' > .tab-content > .tab'),
activeClass = 'active';
$jQ(scope + ' > .tab-menu > .tab').each(function (i, el) {
$jQ(this).add($contentTabs[i]).attr('tab', i + 1);
});
$jQ(scope + ' > .tab-menu > .tab').on((hover ? 'mouseenter' : 'click'), function (e) {
if (!hover) {
e.preventDefault();
}
var tab = $jQ(this).attr('tab');
$jQ(this).add(scope + ' > .tab-content > .tab[tab=' + tab + ']').delay(900).queue(function () {
$jQ(scope + ' > .tab-menu > .tab').addClass(activeClass);
$jQ(this).unqueue();
});
});
$jQ(scope + ' > .tab-menu > .tab').on('mouseleave', function (e) {
if (!hover) {
e.preventDefault();
}
var tab = $jQ(this);
$jQ(scope + ' > .tab-menu > .tab').add(scope + ' > .tab-content > .tab').delay(1000).queue(function () {
$jQ(scope + ' > .tab-menu > .tab').removeClass(activeClass);
$jQ(this).unqueue();
});
});
$jQ(scope + ' > .tab-menu > .tab:first-child').add(scope + ' > .tab-content > .tab:first-child').addClass(activeClass);
},

How can add fade In() effect to each appearance of a div when the mouse click?

How can add fadeIn() effect to each appearance of a div when the mouse click?
So when onmouseclick, yellow part is showing with fadeIn() effect.
Fiddle : http://jsfiddle.net/2ehdW/7/
Script :
window.jQueryclick: function (event) {
if (!event.point.selected) {
$('#testDiv').show();
var chart_data = '<div> Name: ' + event.point.name + ' Share: ' + event.point.y + '</div>';
$('#testDiv').html(chart_data);
} else {
$('#testDiv').hide();
}
}
Add a parameter to .show() method and hide the div before showing it again:
if (!event.point.selected) {
$('#testDiv').hide();
$('#testDiv').show("300"); //or just $('#testDiv').fadeIn();
var chart_data = 'Name: ' + event.point.name + ' Share: ' + event.point.y;
$('#testDiv').html(chart_data);
} else {
$('#testDiv').hide();
}
FIDDLE

Making a button unclickable until jQuery .load() has finished

I'm currently using the following code for my read more buttons:
$(document).ready(function() {
$("a.more-link").attr("href", "");
$("a.more-link").attr("onclick", "return false;");
$('.readmore').each(function(index) {
var $link = $(this);
$(".readmore").prependTo('.' + $link.attr("id") + ' > #bottominfo');
});
$('.readmore').click(function() {
var $link = $(this);
if ( $link.attr("alt") == "read more" ) {
$('.' + $link.attr("id") + ' > #maincontent').load($link.attr("title") + ' #mainarticle', function(index) {
$('.' + $link.attr("id") + ' > #maincontent').hide();
$('.' + $link.attr("id") + ' > #maincontent').slideToggle('slow');
});
$('.' + $link.attr("id") + ' > #maincontent').attr("class", $link.attr("id"));
$link.attr('alt','read less');
} else {
$('#'+ $link.attr("id") + ' > .' + $link.attr("id")).hide();
$link.attr('alt','read more');
}
return false;
});
});
The problem I'm having is that if the user double clicks (or more) on the button it calls the function multiple times.
How do I make the button non-clickable until the .load() have finished?
The easiest would be to add a loading class to the link. I have also just done a quick clean up on your code. I didn't look into how it works but i'm sure if you spend a bit more time you can make it a lot more efficient
$(document).ready(function() {
$("a.more-link").attr("href", "")
.attr("onclick", "return false;");
$('.readmore').each(function(index) {
var $link = $(this);
//wouldn't this call all the elements with "readmore" class????
$(".readmore").prependTo('.' + $link.attr("id") + ' > #bottominfo');
});
$('.readmore').click(function() {
var $link = $(this);
//check if it has already been clicked
if($link.hasClass("loading")) return false;
//add the loading class
$link.addClass("loading");
if ( $link.attr("alt") == "read more" ) {
$('.' + $link.attr("id") + ' > #maincontent').load($link.attr("title") + ' #mainarticle', function(index) {
$('.' + $link.attr("id") + ' > #maincontent').hide()
.slideToggle('slow');
//it's done now and we can remove the loading class so we can click it again
$link.removeClass("loading");
}).attr("class", $link.attr("id"));
$link.attr('alt','read less');
} else {
$('#'+ $link.attr("id") + ' > .' + $link.attr("id")).hide();
$link.attr('alt','read more');
//add it here as well
$link.removeClass("loading");
}
return false;
});
});
Tips: I notice you call the same selectors multiple times. Always check the api doc and see what the methods you are calling do return. Most of them do return the element back, so then you can call the next method without $()
Example: $("div").hide().slideToggle('slow');
Could you not just run the function on .load instead?
$(document).load(function() {
$("a.more-link").attr("href", "");
$("a.more-link").attr("onclick", "return false;");
$('.readmore').each(function(index) {
var $link = $(this);
$(".readmore").prependTo('.' + $link.attr("id") + ' > #bottominfo');
});
$('.readmore').click(function() {
var $link = $(this);
if ( $link.attr("alt") == "read more" ) {
$('.' + $link.attr("id") + ' > #maincontent').load($link.attr("title") + ' #mainarticle', function(index) {
$('.' + $link.attr("id") + ' > #maincontent').hide();
$('.' + $link.attr("id") + ' > #maincontent').slideToggle('slow');
});
$('.' + $link.attr("id") + ' > #maincontent').attr("class", $link.attr("id"));
$link.attr('alt','read less');
} else {
$('#'+ $link.attr("id") + ' > .' + $link.attr("id")).hide();
$link.attr('alt','read more');
}
return false;
});
});

Categories