My function is running twice , I tried using boolean value to stop it but it doesn't work, here is my code :
window.onload = function(){
setTimeout(addbutton, 2940) // Please increase it if it doesn't work, it doesn't work well if your connection is too long
};
function addbutton(){
var hreflink = "/admin/users/delete/"+id;
var Reportuser = document.getElementsByClassName("sg-button sg-button--solid-light sg-button--full-width");
var x = Reportuser.length-1
Reportuser[x].insertAdjacentHTML('beforebegin', '<button id=button class="sg-button sg-button--solid-mint sg-button--small sg-button"><span class="sg-button__text">Delete</span></button>');
console.log("%cButton added","color: blue; font-size: 20px");
function myFunction() {
window.location.href = hreflink;
}
document.getElementById("button").addEventListener("click", myFunction);
}
Refactored and converted your code to a minimal reproducable example using event delegation. The timeout works, once. If you are experiencing problems with connection times, maybe you should check async functions
setTimeout(addbutton, 500);
document.addEventListener("click", handle);
function handle(evt) {
if (evt.target.dataset.clickable) {
console.clear();
return console.log("Yes! It's clicked!");
}
return true;
}
function addbutton() {
[...document.querySelectorAll(".sg-button")].pop()
.insertAdjacentHTML("beforeend", `<button data-clickable="1">Delete</button>`);
console.log("button added to last div.sg-button ...");
}
.sg-button {
margin-bottom: 1.5rem;
border: 1px solid #999;
padding: 0.2rem;
width: 5rem;
text-align: center;
}
.sg-button button {
display: block;
margin: 0 auto;
}
<div class="sg-button sg-button--solid-light sg-button--full-width">1</div>
<div class="sg-button sg-button--solid-light sg-button--full-width">2</div>
Related
I am trying to make this more abstract. I need to find a way to use one function for the same element and different events. I would also like to be able to pass in an element argument but I know I can't do this with a callback. This is what I have thus far:
const divElement = document.querySelector('#test');
divElement.addEventListener(
'mouseenter',
(event) => {
divElement.classList.add('shadow');
console.log(event);
},
false
);
divElement.addEventListener(
'mouseleave',
(event) => {
divElement.classList.remove('shadow');
console.log(event);
},
false
);
Use CSS instead. Never use JS for what can be achieved in CSS.
#test {
background-color: white;
padding: 30px;
transition: all 0.4s ease;
}
#test:hover {
box-shadow: 0 0 10px #000;
}
<div id="test">
Lorem ipsum dolor sit amentur.
</div>
If for some reason you didn't reveal you need it to be event-listener-based, here's what I would do:
const divElement = document.querySelector('#test');
function handleMouseAction({type}) {
this.classList.toggle('shadow', type === 'mouseenter');
}
divElement.addEventListener('mouseenter', handleMouseAction, false);
divElement.addEventListener('mouseleave', handleMouseAction, false);
#test {
padding: 30px;
transition: all 0.4s ease;
}
.shadow {
box-shadow: 0 0 10px #000;
}
<div id="test">
Lorem ipsum dolor sit amentur.
</div>
You can write a helper function and call that from the two callbacks:
const divElement = document.querySelector('#test');
function handleEvent(event, action) {
divElement.classList[action]('shadow');
console.log(event);
}
divElement.addEventListener('mouseenter', (event) => handleEvent(event, 'add'), false);
divElement.addEventListener('mouseleave', (event) => handleEvent(event, 'remove'), false);
Alternatively, you can use partial application with closures to create the two callbacks from one abstract function:
const divElement = document.querySelector('#test');
function makeEventHandler(action) {
return (event) => {
divElement.classList[action]('shadow');
console.log(event);
};
}
divElement.addEventListener('mouseenter', makeEventHandler('add'), false);
divElement.addEventListener('mouseleave', makeEventHandler('remove'), false);
Of course #Wyck is right and in this particular example, you should do everything with CSS only :-)
My way to do that:
const divElement = document.querySelector('#test');
const events = ["mouseenter", "mouseleave"]
events.forEach(event => {
divElement.addEventListener(event, (e) => {
// TODO put logic here.
divElement.classList.add('shadow');
console.log(event);
})
})
Another way to do that, by using onmouseenter="" tag and onmouseleave="" tag, and letting them use the same callback.
const callback = (element) => {
element.classList.add("shadow");
}
.shadow {
display: block;
box-shadow: 0 0 10px black;
}
<div onmouseenter="callback(this)" onmouseleave="callback(this)">Hello World</div>
I'm using a .slideToggle to show a div once an image is clicked. I want the div to disappear 10 seconds after the last time the toggle is clicked. The problem is that if I click the image a few times, the duration is 10 seconds after the first click and not the last. If you view the fiddle (I used a shorter duration for testing) and click the image a few times you will see what I mean.
Does anyone have any idea how I can get this working as desired? Any help would be greatly appreciated!
Fiddle: https://jsfiddle.net/7fy536nv/
Requirements...
The div should show for 10 seconds then disappear
The div will disappear if the image is clicked again
The div will disappear if something outside the div is clicked
HTML
<div class="box-new">
<a href="box-link" id="box-link">
<img src="https://dummyimage.com/100x60/ff0000/fff.png">
</a>
</div>
<div id="empty-box">jkhsahg akjfhsajk fhas jklsad flkasd hfjkashd fjka sdkjfh adskjfhs dakjfh kafh sdah dhjaf</div>
CSS
body, html {
margin: 0;
}
#empty-box {
display: none;
position: absolute;
background: #000;
top: 60px;
width: 240px;
padding: 20px;
left: 0;
color: #fff;
text-align: center;
font-family: "open sans", "arial";
font-size: 14px;
font-weight: 600;
line-height: 18px;
z-index: 1;
}
JS
$('#box-link').click(function(event){
event.stopPropagation();
$("#empty-box").slideToggle(400);
setTimeout(function() {
$("#empty-box").slideUp();
}, 5000);
return false;
});
$("#empty-box").on("click", function (event) {
event.stopPropagation();
});
$(document).on("click", function () {
$("#empty-box").slideUp(400);
});
Assign your call to setTimeout to a variable declared in the outer scope and clear it with clearTimeout in every subsequent event:
var timeout;
$('#box-link').click(function(event){
clearTimeout(timeout);
event.stopPropagation();
$("#empty-box").slideToggle(400);
timeout = setTimeout(function() {
$("#empty-box").slideUp();
}, 5000);
return false;
});
The setTimeout function returns a value that you can cancel using clearTimeout.
So in your code, store the return value, and each time it is clicked, cancel the previous timeout and restart a new one.
var timeout = null;
function test()
{
if( timeout !== null )
clearTimeout(timeout);
timeout = setTimeout(..., 10000);
}
It's quite simple, really. The key is placing your setTimeout in a variable and calling clearTimeout(variable).
Example:
let someVar = false,
someTime = 5000,
msgTimer = document.getElementById('timer'),
timer,
current,
displayTimer = false;
$('.yourButton').on('click', someFunc)
function someFunc() {
if (someVar) {
clearTimeout(someVar) // <<< juice is here
console.log('cleared timeout!')
}
timer = performance.now()
someVar = setTimeout(function () {
clearInterval(displayTimer)
console.log(someTime / 1000 +
' seconds passed since last click...')
someVar = false
displayTimer = false
msgTimer.innerHTML = ''
}, someTime)
/**
* ¯\_(ツ)_/¯
* ignore past this point, rest is timer
*
* ˙ʇᴉ pǝǝu ʇ,uop no⅄ ˙ʎllɐǝɹ
**/
if (displayTimer) {
clearInterval(displayTimer)
displayTimer = false
}
displayTimer = setInterval(function () {
current = performance.now()
msgTimer.innerHTML = Math.max(timer + 5000 - current,0)
.toFixed(2) + 'ms'
}, 15)
}
#timer {
font-family: monospace;
text-align:right;
display: inline-block;
width: 100px;
font-size: 1.2rem;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="yourButton">Don't click. Think.</button>
<span id="timer"></span>
Reduced interval to 5 seconds for faster testing.
Here is a solution to show a div for a maximum of 10 seconds...
And hide it if user clicks anywhere before this delay.
There is no problem with the delay if user clicks often or repeately...
Because I took care of resets.
I created a CodePen, with a timer displayed aside the cart link, to show the time passing.
And here is a CodePen with the exact same code as in the below snippet, if your want to play with it.
var emptyCart = $("#emptyCart");
var cartTimer;
var carMaxTime = 10000;
// Function to hide the cart
var hideCart = function(){
emptyCart.dequeue().slideUp("slow");
}
// Function to show the cart
var showCart = function(){
emptyCart.dequeue().slideDown("slow");
clearTimeout(cartTimer); // Just to be sure We have only one timer running
cartTimer = setTimeout(function(){
hideCart();
},carMaxTime);
}
// Function to handle click on the cart link
$("#clickCart").click(function(){
$(document).off("click",hideCart()); // Just to prevent a slideUp which would counter-act a slideUp
if(emptyCart.is(":hidden")){
showCart();
}
setTimeout(function(){ // 1ms delay to use this event handler on next click.
$(document).on("click",function(){
hideCart();
$(document).off("click",hideCart()); // Unbind this handler once used.
});
},1);
});
#emptyCart{
display:none;
width:100px;
background:#000;
color:#fff;
height:30px;
margin-top:10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="clickCart">
Cart
</div>
<div id="emptyCart">
No items
</div>
After some decent search time, i still haven't found any information for this specific function but i'm sure it can be done.
The site i'm working with has very short pages albeit one. I created a scroll to top button for this single long page with no problems. I want this button to only work for this individual page but when i load another page on the site i get console errors - 'Uncaught TypeError: Cannot read property 'style' of null at scrollFunction'
This is the function i've attempted to use to check the href of the page:
window.onscroll = function() {scrollFunction()};
function scrollFunction() {
if (window.location.href.indexOf("portfolio.html")) {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
document.getElementById("scrollButton").style.display = "block";
} else {
document.getElementById("scrollButton").style.display = "none";
}
}
}
Any guidance would be much appreciated.
This is similar to the answer proposed by Sujen K., but has some differences that simplify code clarity and makes things a bit better for performance:
var elementExists = document.getElementById('scrollButton');
// We can skip the page URL check because in theory this
// behavior is desired on any page with the scrollButton
if (elementExists) {
// By moving the onScroll function into the if statement
// it no longer has to check on pages without scrollButton
// We can also simplify how it is set up.
window.onscroll = function () {
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
// We can reuse elementExists here for a minor
// performance gain instead of having to get it again.
elementExists.style.display = "block";
} else {
elementExists.style.display = "none";
}
};
}
The answer is simple, your statement will be always considered as true, because of indexOf (see spec) return the index (number) of the first founded occurrence, otherwise will return -1.
You should update your code in way:
if (window.location.href.indexOf("portfolio.html") !== -1) {
Have a look at this solution:
http://jsfiddle.net/neeklamy/RpPEe/
$(document).ready(function () {
$(window).scroll(function () {
if ($(this).scrollTop() > 100) {
$('.scrollup').fadeIn();
} else {
$('.scrollup').fadeOut();
}
});
$('.scrollup').click(function () {
$("html, body").animate({
scrollTop: 0
}, 600);
return false;
});
});
Also - consider ditching JS and just give your body an ID (id="something"), then have a link point at (href="#something"). It solves the problem with no scripting at all.
Look this solution:
https://jsfiddle.net/9x204t2o/1/
JS:
$(document).ready(function(){
$(window).scroll(function(){
if ($(this).scrollTop() > 100) {
$('.scrollToTop').fadeIn();
} else {
$('.scrollToTop').fadeOut();
}
});
$('.scrollToTop').click(function(){
$('html, body').animate({scrollTop : 0},800);
return false;
});
});
CSS:
.scrollToTop{
width: 100px;
height: 80px;
padding: 10px;
text-align: center;
background: whiteSmoke;
font-weight: bold;
color: #444;
text-decoration: none;
position: fixed;
bottom: 0;
right: 0;
display: none;
background: url(https://cdn3.iconfinder.com/data/icons/iconic-1/32/arrow_up_alt1-512.png) no-repeat;
background-size: 40px;
background-position: 40px 30px;
}
.scrollToTop:hover{
text-decoration:none;
}
HTML:
<script src="https://code.jquery.com/jquery-3.1.1.js"></script>
Scroll To Top
[...]
Can help?
Here is my code;
$(window).resize(function() {
if ($(window).width() >= 760) {
$('.sidebar-left').one().css("display", "block")
} else if ($(window).width() <= 760) {
$('.sidebar-left').one().css("display", "none")
}
});
var m = $(".menu");
m.addClass('fa-bars');
m.on('click', function() {
if (m.hasClass('fa-bars')) {
m
.removeClass('fa-bars')
.addClass('fa-times');
$(".sidebar-left").css("display", "block")
} else {
m
.removeClass('fa-times')
.addClass('fa-bars');
$(".sidebar-left").css("display", "none")
}
});
.sidebar-left {
width: 100px;
position: fixed;
background-color: black;
height: 100%;
}
.menu.fa {
display: none;
}
#media handheld,
screen and (max-width: 760px) {
.sidebar-left {
display: none;
width: 100%;
background-color: black;
height: 100px;
}
.menu.fa {
display: inline-block;
font-size: 35px;
color: black;
}
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.2/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="menu fa"></div>
<div class="sidebar-left"></div>
And a plunk. (may be easier to test here)
So it's just a simple menu. The issue I have is that currently the resize event will run every time the page is resized, so if I have the menu displayed under 760 pixels it will automatically disappear on resize if I have it opened.
If I take the javascript resize function out completely and leave it to the css, the problem is if I open and close the menu in a smaller window, the display will be set to none when I make the window larger again.
I've tried a few other things, but can't seem to think of a way of doing this. The aim is to just to replicate what the $(window).resize function is doing currently, but for that event to fire only once the window has resized past the points.
Hope the problem is explained clearly.
Thanks
You could use jQuery's one() method, which gets activated exactly once:
$(window).one('resize', function() {
if ($(window).width() >= 760) {
$('.sidebar-left').one().css("display", "block")
} else if ($(window).width() <= 760) {
$('.sidebar-left').one().css("display", "none")
}
});
This will solve your question as asked, but i would actually recommend not disabling the resize event and just handling it better, i.e. checking whether it is proper to open/close the sidebar.
Here's a plugin I made, with a resize begin handler, a resize end handler and of course an on resize handler.
(function() {
var resizeEventHandler = function(resizeTarget, _maxResizeWaitTime, onResizeBeginCB, onResizeEndCB, onResizeCB) {
if(resizeTarget){
var resizeTimer = null;
var resizeBegun = false;
var maxResizeWaitTime = _maxResizeWaitTime || 500;
resizeTarget.addEventListener('resize', function() {
if (!resizeBegun) {
if(onResizeBeginCB){
onResizeBeginCB();
}
resizeBegun = true;
}
if(onResizeCB){
onResizeCB();
}
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function() {
if(onResizeEndCB){
onResizeEndCB();
}
resizeBegun = false;
}, maxResizeWaitTime);
});
}else{
console.error('No resizeTarget specified!');
}
};
this.resizeEventHandler = resizeEventHandler;
}).call(this);
Call it like this:
function onResizeBegin() {
$("body").append('onResizeBegin<br/>')
}
function onResizeEnd() {
$("body").append('onResizeEnd<br/>')
}
function onResize() {
$("body").append('onResize<br/>')
}
var resizeEventHandler1 = new resizeEventHandler(window, 500, onResizeBegin, onResizeEnd, onResize);
JSfiddle: https://jsfiddle.net/sv52m1y2/3/
Normally, I’d set the interval to a variable and then clear it like var the_int = setInterval(); clearInterval(the_int); but for my code to work I put it in an anonymous function:
function intervalTrigger() {
setInterval(function() {
if (timedCount >= markers.length) {
timedCount = 0;
}
google.maps.event.trigger(markers[timedCount], "click");
timedCount++;
}, 5000);
};
intervalTrigger();
How do I clear this? I gave it a shot and tried var test = intervalTrigger(); clearInterval(test); to be sure, but that didn’t work.
Basically, I need this to stop triggering once my Google Map is clicked, e.g.
google.maps.event.addListener(map, "click", function() {
//stop timer
});
The setInterval method returns a handle that you can use to clear the interval. If you want the function to return it, you just return the result of the method call:
function intervalTrigger() {
return window.setInterval( function() {
if (timedCount >= markers.length) {
timedCount = 0;
}
google.maps.event.trigger(markers[timedCount], "click");
timedCount++;
}, 5000 );
};
var id = intervalTrigger();
Then to clear the interval:
window.clearInterval(id);
// Initiate set interval and assign it to intervalListener
var intervalListener = self.setInterval(function () {someProcess()}, 1000);
function someProcess() {
console.log('someProcess() has been called');
// If some condition is true clear the interval
if (stopIntervalIsTrue) {
window.clearInterval(intervalListener);
}
}
the_int=window.clearInterval(the_int);
Simplest way I could think of: add a class.
Simply add a class (on any element) and check inside the interval if it's there. This is more reliable, customisable and cross-language than any other way, I believe.
var i = 0;
this.setInterval(function() {
if(!$('#counter').hasClass('pauseInterval')) { //only run if it hasn't got this class 'pauseInterval'
console.log('Counting...');
$('#counter').html(i++); //just for explaining and showing
} else {
console.log('Stopped counting');
}
}, 500);
/* In this example, I'm adding a class on mouseover and remove it again on mouseleave. You can of course do pretty much whatever you like */
$('#counter').hover(function() { //mouse enter
$(this).addClass('pauseInterval');
},function() { //mouse leave
$(this).removeClass('pauseInterval');
}
);
/* Other example */
$('#pauseInterval').click(function() {
$('#counter').toggleClass('pauseInterval');
});
body {
background-color: #eee;
font-family: Calibri, Arial, sans-serif;
}
#counter {
width: 50%;
background: #ddd;
border: 2px solid #009afd;
border-radius: 5px;
padding: 5px;
text-align: center;
transition: .3s;
margin: 0 auto;
}
#counter.pauseInterval {
border-color: red;
}
<!-- you'll need jQuery for this. If you really want a vanilla version, ask -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p id="counter"> </p>
<button id="pauseInterval">Pause/unpause</button></p>