Why jQuery does not add the class "drop1"? - javascript

I wrote a code for a mobile navigation with sub-menus and tried to add a Class using jQuery and javascript but both methods didn´t adad the Class "drop1" or "drop2" to the clicked element.
I´ve already tried to catch the error, but there was no one
$("ul#main-menu > li[class ^= level1-]")
.prev("img")
.addBack()
.on("click", async ()=> {
try {
await $(this).addClass("drop1");
cl2 = this;
cl2.className += "drop1";
} catch(e) {
console.log(e);
}
})
.each((i, elem)=> {
if($(elem).hasClass("drop1")) {
let newElem = $(elem);
if($(elem).is("img")) {
newElem = $(elem).closest("li");
$(elem).removeClass("drop1");
newElem.addClass("drop1");
}
} else {
return;
}
newElem
.nextUntil("li")
.animate({
"transform": "rotate(180deg)"
}, 300);
newElem
.children("ul[class $= m1]")
.slideDown(300)
.children("li[href = #]")
.on("click", async ()=> {
try {
await $(this).addClass("drop2");
cl1 = this;
cl1.className += "drop2";
} catch(e) {
console.log(e);
}
})
.each((i, el)=> {
if($(el).hasClass("drop2")) {
newEL = $(el);
} else {
return;
}
newEL
.children("ul")
.slideDown(300);
});
});

this is not the clicked element. this inside an arrow function is the same as outside the arrow function, in this case it is probably window. addClass is synchronous, using await on it is a no op.
/*...*/.on("click", function() {
$(this).addClass("drop1");
});
PS: Unhandled errors will bubble up, and will finally be shown in the console. Adding a try { } catch only makes sense if you really want to handle it.

Related

How to run 2 js functions

I have 2 function that I am trying to run, one after another. For some reason they both run at the same time, but the second one does not load properly. Is there a way to run the first function wait then run the second function?:
//run this first
$('#abc').click(function() {
$('.test1').show();
return false;
});
//run this second
(function ($) {
"use strict";
// A nice closure for our definitions
function getjQueryObject(string) {
// Make string a vaild jQuery thing
var jqObj = $("");
try {
jqObj = $(string)
.clone();
} catch (e) {
jqObj = $("<span />")
.html(string);
}
return jqObj;
}
function printFrame(frameWindow, content, options) {
// Print the selected window/iframe
var def = $.Deferred();
try {
frameWindow = frameWindow.contentWindow || frameWindow.contentDocument || frameWindow;
var wdoc = frameWindow.document || frameWindow.contentDocument || frameWindow;
if(options.doctype) {
wdoc.write(options.doctype);
}
wdoc.write(content);
wdoc.close();
var printed = false;
var callPrint = function () {
if(printed) {
return;
}
// Fix for IE : Allow it to render the iframe
frameWindow.focus();
try {
// Fix for IE11 - printng the whole page instead of the iframe content
if (!frameWindow.document.execCommand('print', false, null)) {
// document.execCommand returns false if it failed -http://stackoverflow.com/a/21336448/937891
frameWindow.print();
}
// focus body as it is losing focus in iPad and content not getting printed
$('body').focus();
} catch (e) {
frameWindow.print();
}
frameWindow.close();
printed = true;
def.resolve();
}
// Print once the frame window loads - seems to work for the new-window option but unreliable for the iframe
$(frameWindow).on("load", callPrint);
// Fallback to printing directly if the frame doesn't fire the load event for whatever reason
setTimeout(callPrint, options.timeout);
} catch (err) {
def.reject(err);
}
return def;
}
function printContentInIFrame(content, options) {
var $iframe = $(options.iframe + "");
var iframeCount = $iframe.length;
if (iframeCount === 0) {
// Create a new iFrame if none is given
$iframe = $('<iframe height="0" width="0" border="0" wmode="Opaque"/>')
.prependTo('body')
.css({
"position": "absolute",
"top": -999,
"left": -999
});
}
var frameWindow = $iframe.get(0);
return printFrame(frameWindow, content, options)
.done(function () {
// Success
setTimeout(function () {
// Wait for IE
if (iframeCount === 0) {
// Destroy the iframe if created here
$iframe.remove();
}
}, 1000);
})
.fail(function (err) {
// Use the pop-up method if iframe fails for some reason
console.error("Failed to print from iframe", err);
printContentInNewWindow(content, options);
})
.always(function () {
try {
options.deferred.resolve();
} catch (err) {
console.warn('Error notifying deferred', err);
}
});
}
function printContentInNewWindow(content, options) {
// Open a new window and print selected content
var frameWindow = window.open();
return printFrame(frameWindow, content, options)
.always(function () {
try {
options.deferred.resolve();
} catch (err) {
console.warn('Error notifying deferred', err);
}
});
}
function isNode(o) {
/* http://stackoverflow.com/a/384380/937891 */
return !!(typeof Node === "object" ? o instanceof Node : o && typeof o === "object" && typeof o.nodeType === "number" && typeof o.nodeName === "string");
}
$.print = $.fn.print = function () {
// Print a given set of elements
var options, $this, self = this;
// console.log("Printing", this, arguments);
if (self instanceof $) {
// Get the node if it is a jQuery object
self = self.get(0);
}
if (isNode(self)) {
// If `this` is a HTML element, i.e. for
// $(selector).print()
$this = $(self);
if (arguments.length > 0) {
options = arguments[0];
}
} else {
if (arguments.length > 0) {
// $.print(selector,options)
$this = $(arguments[0]);
if (isNode($this[0])) {
if (arguments.length > 1) {
options = arguments[1];
}
} else {
// $.print(options)
options = arguments[0];
$this = $("html");
}
} else {
// $.print()
$this = $("html");
}
}
// Default options
var defaults = {
globalStyles: true,
mediaPrint: false,
stylesheet: null,
noPrintSelector: ".no-print",
iframe: true,
append: null,
prepend: null,
manuallyCopyFormValues: true,
deferred: $.Deferred(),
timeout: 750,
title: null,
doctype: '<!doctype html>'
};
// Merge with user-options
options = $.extend({}, defaults, (options || {}));
var $styles = $("");
if (options.globalStyles) {
// Apply the stlyes from the current sheet to the printed page
$styles = $("style, link, meta, base, title");
} else if (options.mediaPrint) {
// Apply the media-print stylesheet
$styles = $("link[media=print]");
}
if (options.stylesheet) {
// Add a custom stylesheet if given
$styles = $.merge($styles, $('<link rel="stylesheet" href="' + options.stylesheet + '">'));
}
// Create a copy of the element to print
var copy = $this.clone();
// Wrap it in a span to get the HTML markup string
copy = $("<span/>")
.append(copy);
// Remove unwanted elements
copy.find(options.noPrintSelector)
.remove();
// Add in the styles
copy.append($styles.clone());
// Update title
if (options.title) {
var title = $("title", copy);
if (title.length === 0) {
title = $("<title />");
copy.append(title);
}
title.text(options.title);
}
// Appedned content
copy.append(getjQueryObject(options.append));
// Prepended content
copy.prepend(getjQueryObject(options.prepend));
if (options.manuallyCopyFormValues) {
// Manually copy form values into the HTML for printing user-modified input fields
// http://stackoverflow.com/a/26707753
copy.find("input")
.each(function () {
var $field = $(this);
if ($field.is("[type='radio']") || $field.is("[type='checkbox']")) {
if ($field.prop("checked")) {
$field.attr("checked", "checked");
}
} else {
$field.attr("value", $field.val());
}
});
copy.find("select").each(function () {
var $field = $(this);
$field.find(":selected").attr("selected", "selected");
});
copy.find("textarea").each(function () {
// Fix for https://github.com/DoersGuild/jQuery.print/issues/18#issuecomment-96451589
var $field = $(this);
$field.text($field.val());
});
}
// Get the HTML markup string
var content = copy.html();
// Notify with generated markup & cloned elements - useful for logging, etc
try {
options.deferred.notify('generated_markup', content, copy);
} catch (err) {
console.warn('Error notifying deferred', err);
}
// Destroy the copy
copy.remove();
if (options.iframe) {
// Use an iframe for printing
try {
printContentInIFrame(content, options);
} catch (e) {
// Use the pop-up method if iframe fails for some reason
console.error("Failed to print from iframe", e.stack, e.message);
printContentInNewWindow(content, options);
}
} else {
// Use a new window for printing
printContentInNewWindow(content, options);
}
return this;
};
})(jQuery);
How would I run the first one wait 5 or so seconds and then run the jquery print? I'm having a hard time with this. So the id would run first and then the print would run adter the id="abc" Here is an example of the code in use:
<div id="test">
<button id="abc" class="btn" onclick="jQuery.print(#test1)"></button>
</div>
If I understand your problem correctly, you want the jQuery click function to be run first, making a div with id="test1" visible and then, once it's visible, you want to run the onclick code which calls jQuery.print.
The very first thing I will suggest is that you don't have two different places where you are handling the click implementation, that can make your code hard to follow.
I would replace your $('#abc').click with the following:
function printDiv(selector) {
$(selector).show();
window.setTimeout(function () {
jQuery.print(selector);
}, 1);
}
This function, when called, will call jQuery.show on the passed selector, wait 1ms and then call jQuery.print. If you need the timeout to be longer, just change the 1 to whatever you need. To use the function, update your example html to the following:
<div id="test">
<button id="abc" class="btn" onclick="printDiv('#test1')"</button>
</div>
When the button is clicked, it will now call the previously mentioned function and pass it the ID of the object that you want to print.
As far as your second function goes, where you have the comment **//run this second**, you should leave that alone. All it does is extend you jQuery object with the print functionality. You need it to run straight away and it currently does.

custom when statement not firing functions

I am trying to make a when statement but it is not working as planned. Basically its a function to call another function when try. First before I explain further here is the syntax
when(function() {
//code here
});
Now basically... Think this way.. We have a progressbar.. We also have a custom event such as...
var pBarEvent = document.createEvent('Event');
pBarEvent.initEvent('pbardone', true, true);
document.addEventListener('pbardone', function() {
//code here
});
//if progress bar reaches 100 dispatchEvent
if (document.querySelector(".progress-bar").style.width === 100 + "%")
{
document.dispatchEvent(pBarEvent);
}
Now that piece of code is an example. If the document loads and its for instance at 50% it wont trigger until you add another event such as keydown or click. I dont want to do that I want to do.... "when" progress bar width equals 100% trigger it. Thats basically what needs to happen. So here is the code for the when statement so far (keep in mind its not the best looking one. As I dont normally do this but I wanted to keep this dynamic and who knows someone who later wants to do this can look at this question)
when function
function when(func)
{
var nowActive = false;
if (!typeof func === 'undefined')
{
func = new Function();
}
if (func)
{
nowActive = true;
clearInterval(whenStatementTimer);
}
else
{
nowActive = false;
var whenStatementTimer = setInterval(function() {
switch(func)
{
case true:
{
nowActive = true;
when();
break;
}
case false:
{
nowActive = false;
when();
break;
}
}
}, 1000);
}
if (nowActive === true)
{
func();
}
}
Now this does not work when I go to try something like....
when(function() {
SmartLeadJS.SmartLeadEvents.customEvents.progressBarFull(function() {
alert("100%");
SmartLeadJS.SmartLeadAds.LeadView.ChromeExtension.General.DynamicStyles.$.style("body", "background", "black");
});
});
It does not trigger. I need help possibly getting this when statement to work. What am I doing wrong? What can I do to fix it? No errors get thrown but it never fires.
edit based on answer
Function tried
function when(currentValue)
{
try
{
var o = {};
o.currentValue = currentValue;
o.do = function(func)
{
if (!typeof func === 'undefined')
{
func = new Function();
}
if (this.currentValue)
{
func();
}
else
{
setTimeout(this.do(func), 100);
}
};
return o;
}
catch(e)
{
console.log(e);
}
}
used as
when(true).do(function() {
SmartLeadJS.SmartLeadEvents.customEvents.progressBarFull(function() {
alert("This divs going through changes!!");
SmartLeadJS.SmartLeadAds.LeadView.ChromeExtension.General.DynamicStyles.$.style(".div", "background", "black");
});
});
This does not work. It never fires. But if I use a onclick listener as such it fires
document.addEventListener("click", function() {
SmartLeadJS.SmartLeadEvents.customEvents.progressBarFull(function() {
alert("This divs going through changes!!");
SmartLeadJS.SmartLeadAds.LeadView.ChromeExtension.General.DynamicStyles.$.style(".div", "background", "black");
});
}, false);
function when(statement){
o={};
o.statement=statement;
o.do=function(func){
awhen(this.statement,func);
};
return o;
}
function awhen(statement,func){
if(eval(statement)){
func();
}else{
window.setTimeout(function(){awhen(statement,func);},100);
}
}
Use:
when("true").do(function(){});
It works now :) . Its important to put the condition in ""!

Remove window.location.href from click event

according to current media query i am doing a div clickable. If does not matches max-width: 767px then i am binding the url of the anchor. But if matches the query i do not want to do anything on click. Is there a way to remove it on the else... ?
if (!window.matchMedia('(max-width: 767px)').matches) {
jQuery(el).addClass("clickable");
jQuery(el).click(function (e) {
window.location.href = jQuery(el).find("a").attr("href");
});
}else{
jQuery(el).removeClass("clickable");
jQuery(el).click(function (e) {
window.location.href = ??????
});
}
You should move click event outside the if condition - it will be easier to handle.
var result = !window.matchMedia('(max-width: 767px)').matches;
jQuery(el).click(function (e) {
if (result) {
window.location.href = jQuery(el).find("a").attr("href");
}
}).toggleClass("clickable", result);
Or just use unbind method:
var clickFunction = function (e) {
window.location.href = jQuery(el).find("a").attr("href");
};
if (!window.matchMedia('(max-width: 767px)').matches) {
jQuery(el).addClass("clickable").click(clickFunction);
} else {
jQuery(el).removeClass("clickable").unbind('click', clickFunction);
}
If it is the case you can not edit the code, you can override functionality by adding relevant code after it.
if (window.matchMedia('(max-width: 767px)').matches) {
jQuery(el).removeClass("clickable");
}

Mini Refactoring Javascript Code

I want to optimize my Js code, at the moment i am rewriting the same function to launch a game in a popup. The only difference between the functions (open_web_client, open_web_client_2) is the openPopup size
I would like to use the same function for both games launched in the pop up, how can i use just a function for both in order to avoid repeating all the code?
This is the code
$(document).ready(function() {
web_client();
});
var web_client = function() {
var open_web_client = function(e) {
e.preventDefault();
if (!app.userIsLoggedIn()) {
app.showLoginPopup(translate.login_required_to_play_for_real);
} else {
if (Utils.analytics_enabled()) {
Utils.analytics_track_click('Play', $(this).attr("data-game-name"));
}
new GameWindow($(this).attr('href'), 'LOBBY').openPopup('1100x800');
}
}
var open_web_client_2 = function(e){
e.preventDefault();
if(!app.userIsLoggedIn()){
app.showLoginPopup(translate.login_required_to_play_for_real);
} else {
if(Utils.analytics_enabled()){
Utils.analytics_track_click('Play', $(this).attr("data-game-name"));
}
new GameWindow($(this).attr('href'), 'LOBBY').openPopup('1024x768');
}
}
if ($("a.ea_client").size() > 0) {
$('a.ea_client').on("click", open_web_client);
$('a.oneworks_client').on("click", open_web_client_2);
}
};
The only difference between the two functions is the value that is passed to openpopup.
So create a common function and pass the dimensions to the event handler.
var open_web_client = function(e) {
e.preventDefault();
if (!app.userIsLoggedIn()) {
app.showLoginPopup(translate.login_required_to_play_for_real);
} else {
if (Utils.analytics_enabled()) {
Utils.analytics_track_click('Play', $(this).attr("data-game-name"));
}
//here the hardcoded value is replaced with e.data.dim
new GameWindow($(this).attr('href'), 'LOBBY').openPopup(e.data.dim);
}
};
then modify the handler code to pass the dimensions uniquely
$('a.ea_client').on("click",{dim:'1100x800'}, open_web_client);
$('a.oneworks_client').on("click",{dim:'1024x768'}, open_web_client);
arguments passed this way to handlers can be accessed through data property present in the event object.
The only difference between the functions (open_web_client, open_web_client_2) is the openPopup size
That is basically begging to become a parameter of your function:
function open_web_client(e, size) {
e.preventDefault();
if (!app.userIsLoggedIn()) {
app.showLoginPopup(translate.login_required_to_play_for_real);
} else {
if (Utils.analytics_enabled()) {
Utils.analytics_track_click('Play', $(this).attr("data-game-name"));
}
new GameWindow($(this).attr('href'), 'LOBBY').openPopup(size);
}
}
$('a.ea_client').on("click", function(e) {
open_web_client(e, '1100x800');
});
$('a.oneworks_client').on("click", function(e) {
open_web_client(e, '1024x768');
});
A littlebit more advanced technique is to use a closure, with a function that creates the listener:
function make_web_client_opener(size) {
return function open_web_client(e) {
e.preventDefault();
if (!app.userIsLoggedIn()) {
app.showLoginPopup(translate.login_required_to_play_for_real);
} else {
if (Utils.analytics_enabled()) {
Utils.analytics_track_click('Play', $(this).attr("data-game-name"));
}
new GameWindow($(this).attr('href'), 'LOBBY').openPopup(size);
}
};
}
$('a.ea_client').on("click", make_web_client_opener('1100x800'));
$('a.oneworks_client').on("click", make_web_client_opener('1024x768'));

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