How make javascript function work only one time - javascript

How to make Javascript function work only one time ?
if (window.location.hash) {
$(document).ready(function () {
var id = window.location.hash;
$(id).trigger('click');
});
$('li').click(function () {
$(this).prependTo($(this).parent());
});
}
I need auto-click on that li element which link user comes to website. web.com/#2 (list order - 2 1 3 4 5) , web.com/#4 (list order - 4 1 2 3). but i want than user stay in website with hash url list elements stay in their places then user click for example on 3 list element he must stay and his place so list order (4 1 2 3). I just need change list order by url hash on load page.

I solved it
if (window.location.hash) {
$('li').one('click',function () {
if (!window.run){
$(this).prependTo($(this).parent());
window.run = true;
}
});
$(document).ready(function () {
var id = window.location.hash;
$(id).trigger('click');
});
}

In your particular case the simplest solution is to use .one(), which unbinds the handler after running it the first time:
$('li').one('click',function () { ... }
Another approach is to have the function redefine itself to a no-op after it runs. This can be useful in some cases when there isn't a convenient event handler to unbind:
var oneTimeFunction = function() {
console.log("This will only happen once.");
oneTimeFunction = function() {};
}

Related

How can I loop variables with Jquery

I'm new with Javascript and Jquery and I'm facing a small problem.
I'm trying to make sure that if a given link exists, hovering over this link will bring up a popup with the fadeToggle().
So I wrote this code that works:
if ($('.link-1')) {
$('.link-1').mouseover(function () {
$('.popup-1').fadeToggle();
})
.mouseout(function () {
$('.popup-1').fadeToggle();
})
}
But, instead of repeating it ten times, I wanted to write a loop, like this:
var number = 0;
while (number < 10) {
var popup = '.popup-' + number;
var link = '.link-' + number;
if ($(link)) {
$(link).mouseover(function () {
$(popup).fadeToggle();
})
.mouseout(function () {
$(popup).fadeToggle();
})
}
number++;
}
But it does not work. Could you help me please ?
I thank you in advance !
Based on your comments, I'd recommend this approach.
Add a data attribute to each link that corresponds with the popup you want to fire. This will look something like this:
<a href='#' class='link-1' data-popup='popup-1'> Link </a>
Then add a hover event to ALL links, that performs an action if it has the data type:
//hover event on all links(assumes anchor tags)
$('a').mouseover(function () {
if ($(this).attr('data-popup')) {
let popup = '.' + $(this).attr('data-popup');
$(`${popup}`).fadeToggle();
}})
.mouseout(function () {
if ($(this).attr('data-popup')) {
let popup = '.' + $(this).attr('data-popup');
$(`${popup}`).fadeToggle();
}})
You could also make this a single line function using .hover instead of .mouseover and .mouseout if it fits your use case
**refactoring process is added here:
//start with the original function
$('a').hover(function () {
if ($(this).attr('data-popup')) {
let popup = '.' + $(this).attr('data-popup');
$(`${popup}`).fadeToggle();
}})
//consolidate the enter and exit events using .hover()
$('a').hover(function () {
if ($(this).attr('data-popup')) {
let popup = '.' + $(this).attr('data-popup');
$(`${popup}`).fadeToggle();
}})
//remove the if statement, because the function firing without a pop up won't result in any effect
$('a').hover(function () {
let popup = '.' + $(this).attr('data-popup');
$(`${popup}`).fadeToggle();
})
//substitute the variable directly into the jquery tag
$('a').hover(function () {
$(`'.${$(this).attr('data-popup')}`).fadeToggle();
})
// use an ES6 arrow function to make this a one line function
$('a').hover(() => $(`.${$(this).attr('data-popup')}`).fadeToggle())
//as is, this function won't work, because the arrow function binds the "this" keyword differently.
//Event handlers have an optional parameter that is an event JSON object, so we pass that into the function.
//Because it is a parameter, and is used as a variable we can call event "e" for short
//target is a property of the JSON object 'event' that indicates what specific element is triggering the event
// You can console log "e" to see what other values are baked into the event
$('a').hover((e) => $(`.${$(e.target).attr('data-popup')}`).fadeToggle())
//lastly, because we are using an anonymous arrow function with only one parameter, we can omit the parenthesis around the paremeter
$('a').hover(e => $(`.${$(e.target).attr('data-popup')}`).fadeToggle())
The end result is the one liner below!
$('a').hover(e => $(`.${$(e.target).attr('data-popup')}`).fadeToggle())
Additional info on data attributes can be found here:
https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes
welcome to the web community :-)
My jQuery skills are a bit rusty, but I recall, that there is an Attribute Contains Selector, which you could combine with .each() like so:
$('[class*="link-"]').each(function (index, link) {
$('[class="popup-"' + index + '"]').each(function (_, popup) {
$(link)
.mouseover(function () {
$(popup).fadeToggle();
})
.mouseout(function () {
$(popup).fadeToggle();
})
}
}
The second index is not interesting, that's why I named the argument „_”.
Let me know, whether it still works
If your objects are in order from link-1 to link-10, you can try this method
Loop object that has class "link-[number]" using each function
save number using index + 1
give action to object that have been hovered
so the code will be like this:
$('[class*="link-"]').each(function (index) {
var number = index + 1; //index start from 0, so it need to add + 1
$(this)
.mouseover(function () {
$('[class="popup-' + number+ '"]').fadeToggle();
})
.mouseout(function () {
$('[class="popup-' + number+ '"]').fadeToggle();
})
});
But if your object are not in order from link-1 to link-10, I recommend to use custom data attribute in your HTML code.
Example:
<a class="link-1" data-number="1">test 1</a>
<div class="popup-1" style="display:none">
test 1 popup
</div>
Then change number variable to this code:
var number = $(this).attr("data-number");
It will more save.
Hope it helps.

Want to set show/hide script visible by default

i want to set a show/hide js script that is using localstorage on by default.
$(document).ready(function () {
var sidebarVisible = localStorage.getItem('sidebar') == 'true';
$('#sidebar').toggle(sidebarVisible);
$('.bgcontainer_center').toggleClass('clicked', sidebarVisible);
$("#toggle").click(function () {
$("#sidebar").toggle("slow", function () {
localStorage.setItem('sidebar', $('#sidebar').is(':visible'));
});
$(".bgcontainer_center").toggleClass('clicked');
});
});
This is the link to it https://jsfiddle.net/eo12xw79/67/
I can't seem to find how to set it on by default.
The reason it isn't toggled is because the sidebar key isn't present in the browser's localstorage the first time we visit the page.
There is a very simple solution, just have to check if the sidebar key exists in the localstorage and if not, create it.
$(document).ready(function () {
// BEGIN
if(!localStorage.getItem('sidebar')) {
localStorage.setItem('sidebar', 'true');
}
// END
var sidebarVisible = localStorage.getItem('sidebar') == 'true';
$('#sidebar').toggle(sidebarVisible);
$('.bgcontainer_center').toggleClass('clicked', sidebarVisible);
$("#toggle").click(function () {
$("#sidebar").toggle("slow", function () {
localStorage.setItem('sidebar', $('#sidebar').is(':visible'));
});
$(".bgcontainer_center").toggleClass('clicked');
});
});
EDIT : I think it's useless, why ?
Because you will use the localstorage for a single variable that has no real importance.
After, this is only a personal opinion, it depends on your needs.
DUPLICATE : How to check whether a Storage item is set?

Show a sub-menu using JQuery

I need some help making a sub-menu appear within 2s after the page loads instead of when the user clicks on it. I'm using JQuery. That file is the core of the website. I need it to stay opened.
Here's the code I have at the moment, I tried to change that on.Click event but it didn't work.
The handleSidenarAndContentHeight(); function resizes the menu items after the sub-menu appears.
jQuery('.page-sidebar li > a').on('click', function (e) {
if ($(this).next().hasClass('sub-menu') === false) {
return;
}
var parent = $(this).parent().parent();
parent.children('li.open').children('a').children('.arrow').removeClass('open');
parent.children('li.open').children('a').children('.arrow').removeClass('active');
parent.children('li.open').children('.sub-menu').slideUp(350);
parent.children('li').removeClass('open');
parent.children('li').removeClass('active');
var sub = jQuery(this).next();
if (sub.is(":visible")) {
jQuery('.arrow', jQuery(this)).removeClass("open");
jQuery(this).parent().removeClass("active");
sub.slideUp(350, function () {
handleSidenarAndContentHeight();
});
} else {
jQuery('.arrow', jQuery(this)).addClass("open");
jQuery(this).parent().addClass("open");
sub.slideDown(350, function () {
handleSidenarAndContentHeight();
});
}
e.preventDefault();
});
Working with a 2 second timeout should do the trick!
jQuery(document).ready(function(){
// Open Parent here
setTimeout(function(){
// Open Child here
}, 2000)
});
There is a simple javascript function you can use, the setTimeout function.
The code follows like this :
setTimeout(function() {yourFunctyion();}. delayTimeInMiliseconds);
This will call your function after the number of second(in ms).
There is also a plugin I've used. It has oneTime and everyTime methods.
jQuery timers plugin

How can i add $(document).ready(function(){}) after a function in java script

What I want to do is I have a code like below :
$(document).ready(
function(){
var currentPage = window.location.pathname;
$('#main-menu-list').find('a[href^="' + currentPage + '"]').closest('li').addClass('active');
}
)
And now I want to add this code to add and get work with other code. I need to add this code after this one:
function () {
/* If there are forms, make all the submit buttons in the page appear
disabled and prevent them to be submitted again to avoid accidental
double clicking. See Issue 980. */
jQuery(function() {
/* Delegate the function to document so it's likely to be the last event
in the queue because of event bubbling. */
jQuery(document).delegate("form", "submit", function (e) {
var form = jQuery(this);
if (form.hasClass("form_disabled")) {
e.preventDefault();
return false;
}
else {
form
.addClass("form_disabled")
.find(":submit")
.addClass("disabled");
}
// Reactivate the forms and their buttons after 3 secs as a fallback.
setTimeout(function () {
form
.removeClass("form_disabled")
.find(":submit")
.removeClass("disabled");
}, 3000);
});
});
}
How can I get this done. Please help me out to solve this problem.
You can create document.ready() anywhere in script. It is not necessary all of your code should be in ready function.
You can create instance variable for function and call it where you need:
$(document).ready(
var myFunc = function(){
var currentPage = window.location.pathname;
//other code
}
...
//and invoke it where you need
myFunc();
)
First, name the long function in your code section, for example, launchFormControls(). And then define the function outside of the document ready event. A good practice would be to do so and keep the ready event body clean.
For example:
function launchFormControls() {
//function code
}
Or, in other syntax:
var launchFormControls = function() {
//function code
}
Second, call your function from within the document ready event. Your function will be defined and able to call once the document is loaded. This code can be placed at the top or bottom of your javascript section or file.
For example:
$(document).ready(function(){
var currentPage = window.location.pathname;
$('#main-menu-list').find('a[href^="' + currentPage+'"]').closest('li').addClass('active');
launchFormControls();
});

jQuery switching between more than two classes

I've already posted a question about jQuery toggle method here
But the problem is that even with the migrate plugin it does not work.
I want to write a script that will switch between five classes (0 -> 1 -> 2 -> 3 -> 4 -> 5).
Here is the part of the JS code I use:
$('div.priority#priority'+id).on('click', function() {
$(this).removeClass('priority').addClass('priority-low');
});
$('div.priority-low#priority'+id).on('click' ,function() {
$(this).removeClass('priority-low').addClass('priority-medium');
});
$('div.priority-medium#priority'+id).on('click', function() {
$(this).removeClass('priority-medium').addClass('priority-normal');
});
$('div.priority-normal#priority'+id).on('click', function() {
$(this).removeClass('priority-normal').addClass('priority-high');
});
$('div.priority-high'+id).on('click', function() {
$(this).removeClass('priority-high').addClass('priority-emergency');
});
$('div.priority-emergency'+id).on('click', function() {
$(this).removeClass('priority-emergency').addClass('priority-low');
});
This is not the first version of the code - I already tried some other things, like:
$('div.priority#priority'+id).toggle(function() {
$(this).attr('class', 'priority-low');
}, function() {
$(this).attr('class', 'priority-medium');
}, function() {
...)
But this time it only toggles between the first one and the last one elements.
This is where my project is: strasbourgmeetings.org/todo
The thing is that your code will hook your handlers to the elements with those classes when your code runs. The same handlers remain attached when you change the classes on the elements.
You can use a single handler and then check which class the element has when the click occurs:
$('div#priority'+id).on('click', function() {
var $this = $(this);
if ($this.hasClass('priority')) {
$this.removeClass('priority').addClass('priority-low');
}
else if (this.hasClass('priority-low')) {
$this.removeClass('priority-low').addClass('priority-medium');
}
else /* ...and so on... */
});
You can also do it with a map:
var nextPriorities = {
"priority": "priority-low",
"priority-low": "priority-medium",
//...and so on...
"priority-emergency": "priority"
};
$('div#priority'+id).on('click', function() {
var $this = $(this),
match = /\bpriority(?:-\w+)?\b/.exec(this.className),
current = match && match[0],
next = nextPriorities[current];
if (current) {
$this.removeClass(current).addClass(next || 'priority');
}
});
[edit: working demo]
Assuming you have 'priority' as the default class already on the element at the initialization phase, this will cycle through the others:
$('div#priority' + id)
.data('classes.cycle', [
'priority',
'priority-low',
'priority-medium',
'priority-normal',
'priority-high',
'priority-emergency'
])
.data('classes.current', 0)
.on('click', function () {
var $this = $(this),
cycle = $this.data('classes.cycle'),
current = $this.data('classes.current');
$this
.removeClass(cycle[current % cycle.length])
.data('classes.current', ++current)
.addClass(cycle[current % cycle.length]);
});
I have tried myself to do this with the sole help of toggleClass() and didn't succeeded.
Try my method that declares an array with your five classes and toggles dynamically through
them.Do adapt to your own names.
//variable for the classes array
var classes=["one","two","three","four","five"];
//add a counter data to your divs to have a counter for the array
$('div#priority').data("counter",0);
$(document).on('click','div#priority',function(){
var $this=$(this);
//the current counter that is stored
var count=$this.data("counter");
//remove the previous class if is there
if(($this).hasClass(classes[count-1])){
$(this).removeClass(classes[count-1]));
}
//check if we've reached the end of the array so to restart from the first class.
//Note:remove the comment on return statement if you want to see the default class applied.
if(count===classes.length){
$this.data("counter",0);
//return;//with return the next line is out of reach so class[0] wont be added
}
$(this).addClass(classes[count++]);
//udpate the counter data
$this.data("counter",count);
});
//If you use toggleClass() instead of addClass() you will toggle off your other classes.Hope is a good answer.

Categories