Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
I have around 20 buttons that view different type av boxes when clicked, so my JS code is really long. The function works perfect but im wondering if there is a way to shorten this code or make it more cleaner?
// Content lvl 1
function show(sel) {
var el = $(sel);
el.fadeToggle();
$('.showmore-1').not(el).fadeOut("slow");
}
$('.showmore-1').hide();
$('#click-1a').click(function () {
show('#showmore-1a');
});
$('#click-1b').click(function () {
show('#showmore-1b');
});
// Content lvl 2
function show(sel) {
var el = $(sel);
el.fadeToggle();
$('.showmore-2').not(el).fadeOut("slow");
}
$('.showmore-2').hide();
$('#click-2a').click(function () {
show('#showmore-2a');
});
$('#click-2b').click(function () {
show('#showmore-2b');
// Content lvl 3
function show(sel) {
var el = $(sel);
el.fadeToggle();
$('.showmore-3').not(el).fadeOut("slow");
}
$('.showmore-3').hide();
$('#click-3a').click(function () {
show('#showmore-3a');
});
$('#click-3b').click(function () {
show('#showmore-3b');
});
And this will continue to click 20 i maybe will do even more.
YES
$("[id^=click]").click(function (e) { //match elements with ID's starting with "click"
oldSelector = e.target.id; //get the ID of the clicked element
newSelector = oldSelector.replace("click", "showmore"); //replace string
show(newSelector);
});
Advantage is that the code keeps working if you add more or less buttons the same way. No need to update this code for it, nor the HTML itself.
Body as 1 liner:
$("[id^=click]").click(function (e) {
show(e.target.id.replace("click", "showmore"));
});
If your HTML is editable, try something like this:
<button class="clickable" data-for="#showmore-1">Click</button>
Then your jQuery becomes:
$(function() {
$(document.body).on("click",".clickable",function(e) {
e.preventDefault();
show(this.getAttribute("data-for"));
});
function show(sel) { ... }
});
If your elements are like:
<div id="click-1">click me</div>
make them like:
<div class="showing-trigger" data-target-id="showmore-1">click me</div>
and then your handlers could be:
$('.showing-trigger').on('click', function () {
show('#' + $(this).data('target-id'));
});
Note that with this code your triggers can show a div with any id.
for ( var counter = 0; counter < 20; counter++)
{
$('#click-' + counter).click(function () {
var idCounter = $( this ).attr( "id" ).split( "-" )[1];
show('#showmore-' + idCounter );
});
}
or better yet, bind a click event to a class rather than on id
Try this:
for(var i=1,l=21; i<l; i++){
(function(i){ // closure scopes off i so it's not at end of loop when Event occurs
$('#click-'+i).click(function(){
$('.showmore').fadeOut('slow', function(){ // fade showmore class out
$('#showmore-'+i).show(); // show just the one you want
});
});
})(i);
}
It can be shortened to this:
$("[id^= click]").click(function (e) {
oldSelector = e.target.id; //get the ID of the clicked element
newSelector = oldSelector.replace("click", "showmore");
show(newSelector);
});
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed last year.
Improve this question
I have the below code whichs executes every 5 seconds. However i would like to return different data each time.
For example:
First interval = top level data (level.php)
Second interval = top skill data (skill.php)
Third interval = top magic data (magic.php)
And once the third interval is done... return to level.php to start the sequence again
Can someone tell me how would i modify the code to achieve what i want?
<script>
var text = "";
var toplevel = function() {
$.ajax({
type : 'GET',
url : '/pages/level.php',
success : function(data){
text = data;
$("#tops").fadeOut( "normal", function() {
$('#tops').html(data);
$("#tops").fadeIn( "normal", function() {});
});
},
});
};
$(document).ready(function(){
setInterval(toplevel, 5000);
toplevel();
});
</script>
You could have an array of URLs, always send the request to the first one, and rotate the array order on success:
function toplevel(urls) {
return function () {
$.get(urls[0]).done(function (data) {
urls.push(urls.shift());
$("#tops").fadeOut("normal", function () {
$('#tops').html(data).fadeIn( "normal");
});
});
}
};
$(function () {
var switcher = toplevel(['/pages/level.php', '/pages/skill.php', '/pages/magic.php']);
setInterval(switcher, 5000);
switcher();
});
I have multiple divs in one html page under common wrapper class.
I am using hide and show method on clicking next and previous option.
What I am trying to achieve: On page reload/refresh, the div which is showing currently should show after page reload.
So in short if you reload/refresh from pink screen, it should show same pink screen after page reload.
What I tried: I am storing the display properties (none or block) is local storage and on page reload trying to give same properties to divs again. Most of the responses and solution I checked in Stack overflow is regarding opening the same tab when refresh. but my case is what in same tab I have multiple div and I want to open from the same state which it was earlier.
Logic I used:
$(window).on('load', function(){
var disp = localStorage.getItem("disp");
var ustatus = JSON.parse(disp);
$(".chk").text(ustatus);
for (var x=ustatus; x<ustatus.length; x++){
$(".pg"+x).css("display", ustatus[x]);
}
});
This is fiddle link I tried:
Page reload demo JS Fiddle link
Your HTML and CSS code is perfect but you need to make corrections in your JavaScript code.
Observation 1 : You "for" loop to assign display style has problem with variable x. You need to assign integer value to x.
Observation 2 : You need to remove that "display" style from "div" elements when you click on "next" and "previous" links.
Hear is new Js fiddle link with updated code.
$(window).on('load', function () {
//localStorage.removeItem("disp");
var disp = localStorage.getItem("disp");
var ustatus = JSON.parse(disp);
$(".chk").text(ustatus);
for (var x = 1; x <= ustatus.length; x++) {
$(".pg" + x).css("display", ustatus[x-1]);
}
});
$(".next").on("click", function () {
$(this).parent().addClass("off").removeClass("on").removeAttr("style");
$(this).parent().next().addClass("on").removeClass("off").removeAttr("style");
});
$(".prev").on("click", function () {
$(this).parent().addClass("off").removeClass("on").removeAttr("style");
$(this).parent().prev().addClass("on").removeClass("off").removeAttr("style");
});
$(window).on('beforeunload', function () {
var display = $(".clr").map(function () {
return $(this).css("display");
}).get();
localStorage.setItem("disp", JSON.stringify(display));
});
You can also download this file. Please run index.html to see the output.
You don't really need the on class:
$(window).on('load', function(){
var disp = localStorage.getItem("disp");
var ustatus = JSON.parse(disp);
$(".chk").text(ustatus);
for (var x=0; x<ustatus.length; x++){
$(".pg"+(x+1)).toggleClass("off", ustatus[x]);
}
});
$(".next").on("click", function(){
$(this).parent().addClass("off");
$(this).parent().next().removeClass("off");
});
$(".prev").on("click", function(){
$(this).parent().addClass("off");
$(this).parent().prev().removeClass("off");
});
$(window).on('beforeunload', function(){
var display = $(".clr").map(function(){
return $(this).hasClass("off");
}).get();
localStorage.setItem("disp", JSON.stringify(display));
});
Fiddle
note: you can't use $(window).on('load', ...) in a fiddle - the JS in the editor is run on load
EDIT: you might also want to validate ustatus before applying it, something like
if (Array.isArray(ustatus) && ustatus.filter(x => x === true).length === 1) {
for (var x=0; x<ustatus.length; x++){
$(".pg"+(x+1)).toggleClass("off", ustatus[x]);
}
}
You can do it without using display, you can use on and off classes, i think that's why they are created for
$(window).on('load', function(){
var disp = localStorage.getItem("disp");
var ustatus = JSON.parse(disp);
if(ustatus!=undefined){
$(".chk").text(ustatus);
for (var x=1; x<=ustatus.length; x++){
if(ustatus[x-1]=='on'){
$(".pg"+x).addClass("on").removeClass("off");
}
else{
$(".pg"+x).addClass("off").removeClass("on");
}
}
}
$(".next").on("click", function(){
$(this).parent().addClass("off").removeClass("on");
$(this).parent().next().addClass("on").removeClass("off");
});
$(".prev").on("click", function(){
$(this).parent().addClass("off").removeClass("on");
$(this).parent().prev().addClass("on").removeClass("off");
});
$(window).on('beforeunload', function(){
var display = $(".clr").map(function(){
if($(this).hasClass('on'))
return 'on';
else
return 'off';
}).get();
localStorage.setItem("disp", JSON.stringify(display));
});
});
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Why bind won't work after setInterval?
var i = 0;
$('.click').bind('click').click(function(){
var thisclick = $(this);
var move = setInterval(function(){
if(i < 30){
i++;
thisclick.unbind('click');
}
else{
thisclick.bind('click');
clearInterval(move);
}
},3000)
})
As of jQuery 1.7 .on() method is preferred, but the actual issues you have are
you are not providing handler for the second binding ( in case you want to rebind the click with the same handler )
you need to reset/clear the counter, since it's a closure variable it'll always be in 30 once reached.
$('.click').on('click', handler);
var i = 0;
function handler(e) {
e.preventDefault();
var thisclick = $(this);
var move = setInterval(function () {
if (i < 10) {
i++;
thisclick.off('click');
} else {
thisclick.on('click', handler);
i = 0; // reset here
clearInterval(move);
}
}, 1000);
};
DEMO
You have to pass function and time to setInterval. Like following example and you are missing time is your code.
setInterval(function(){alert("Hello")}, 3000);
So Change would be
setInterval(function(){
if(i < 30){
i++;
thisclick.unbind('click');
}
else{
thisclick.bind('click');
clearInterval(move);
}
},3000)//Give your value here
Binding to the click event has nothing to do with the issue.
setInterval() expects two parameters: the function to call when triggered, and the time interval in which to trigger said function (in milliseconds)
For example:
var myInterval = setInterval(myFunction, 200);
This will trigger the "myFunction" method every 200 milliseconds.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
Can someone assist me in trying to get pause on hover working with this example. Essentially I need it to do the following.
Pause interval On Hover
Highlight item hovered over
on hover out resume rotate
Code (fiddle demo):
var $f = $('ul').find('.frame');
function recursive(i) {
$f.removeClass('showing').eq(i).addClass('showing');
setTimeout(function () {
recursive(++i % $f.length)
}, 1000);
}
recursive(0);
Working DEMO
You might need to tweak this a bit to fit into your requirements. Basically the idea is to clear interval on mouse over and resume recursion on mouseout & keep a reference to count.
var $f = $('ul').find('.frame'),
timeOut,
count;
function recursive(i) {
count = i;
$f.removeClass('showing').eq(i).addClass('showing');
timeOut = setTimeout(function () {
recursive(++i % $f.length)
}, 1000);
}
$('ul li').hover(function(){
clearTimeout(timeOut);
});
$('ul li').mouseout(function(){
recursive(count);
});
recursive(0);
Add this
$(".frame").hover(function () {
clearTimeout(t);
console.log(this);
$(this).addClass("showing");
}, function () {
recursive(0);
});
Fiddle
Try this:
var $f = $('ul').find('.frame');
$('ul li').hover(function(){
$f.removeClass('showing');
$(this).addClass('showing');
clearTimeout(timer);
}, function(){
recursive($(this).index());
});
function recursive(i) {
$f.removeClass('showing').eq(i).addClass('showing');
timer = setTimeout(function () {
recursive(++i % $f.length)
}, 1000);
}
recursive(0);
demo
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
Ive posted a similar question before, yet again i find my self stupidly copy and pasting code.
is there anyway i can combine the following, im sure there is.. Please help.. Im in the learning process.
See i have the follow:
$(document).on('blur', 'input.email', function() {
validate_Email_Input(this);
});
$(document).on('blur', 'input.id', function() {
validate_Id_Input(this);
});
$(document).on('blur', 'input.pass', function() {
validate_Pass_Input(this);
});
$(document).on('blur', 'input.town', function() {
validate_Town_Input(this);
});
$(document).on('blur', 'input.relation', function() {
validate_Relation_Input(this);
});
$(document).on('blur', 'input.contact', function() {
validate_Relation_Input(this);
});
and for all of those i have separate function, here's an example of one:
function validate_Email_Input(el) {
var $this = $(el);
var input_groups = $this.parent();
var isValid = true;
$.each(input_groups , function(i){
var inpg = input_groups[i];
email_values = $.map($(inpg).children('input'), function(e,i){
return $(e).val();
}).join('');
isValid = isValid && validate_Email(email_values, input_groups.parent().parent().parent());
});
return isValid;
}
I really want to learn how to write efficient code, Any Help Greatly apreciated...
I don't know if this helps at all. but what i'm trying to do is validate everything and have messages pop out for each specific field. This is my first really big project in jQuery and I thought i may as well show you all what im working on: http://jsfiddle.net/dawidvdh/36BLm/
sample of a valid ID: 85 0929 5266086
This should do the exact same thing as your first block of code:
$(document)
.on('blur', 'input.email', validate_Email_Input)
.on('blur', 'input.id', validate_Id_Input)
.on('blur', 'input.pass', validate_Pass_Input)
.on('blur', 'input.town', validate_Town_Input)
.on('blur', 'input.relation', validate_Relation_Input)
.on('blur', 'input.contact', validate_Relation_Input);
Edit: commenter Ian is right. In order for this to work you need to change the second block of code to:
function validate_Email_Input() {
var $this = $(this); // This line has changed
var input_groups = $this.parent();
var isValid = true;
$.each(input_groups , function(i){
var inpg = input_groups[i];
email_values = $.map($(inpg).children('input'), function(e,i){
return $(e).val();
}).join('');
isValid = isValid && validate_Email(email_values, input_groups.parent().parent().parent());
});
return isValid;
}
You could create an object mapping each field selector to its validator function, and loop from within a single event handler:
$(document).on('blur', function(e) {
var validators = {
'input.email' : validate_Email_Input,
'input.id' : validate_Id_Input
// etc
};
for(var field in validators) {
if($(e.target).is(field)) {
validators['field'](e.target);
}
}
}
To refactor it you can create a model:
var myInputsModel = [
{ a: 'input.email' }, // you can store all the information you want in the model...
{ a: 'input.id' },
etc...
];
so then you got just one function for all of them:
$.each(myInputsModel, function(i, v) {
$(document).on('blur', v.a, function() {
// One function for all of them.
mySingleFunction(this);
});
});
function mySingleFunction(el) {
var $this = $(el);
var input_groups = $this.parent();
var isValid = true;
$.each(input_groups , function(i){
var inpg = input_groups[i];
email_values = $.map($(inpg).children('input'), function(e,i){
return $(e).val();
}).join('');
isValid = isValid && validate_Email(email_values, input_groups.parent().parent().parent());
});
return isValid;
}
$("#my_form").submit(function(e){
var valid = 1;
var error_msg = "";
//validate fields here, if fails set valid to 0 and error_msg to whatever
if(!valid){
e.preventDefault();
alert(error_msg);
}
});
Here's one approach.
Start by giving all of the html elements a common class, and use a data attribute for the value type
<input type="text" class="validate" data-value-type="town" />
Sample jQuery + javascript
// Make an object matching strings to functions
var functionMap = {
email: emailFunction(),
id: idFunction(),
pass: passFunction(),
town: townFunction,
relation: relationFunction(),
contact: contactFunction
}
function validate(element){
// see if the attribute being checked against has a matching entry in functionMap
if(functionMap[element.data('value-type')] !== undefined){
// call the function if it's there
functionMap[element.data('value-type')];
}
}
$(document).on('blur', '.validate', function(){
validate($(this));
}