Combining multiple similar functions into one - javascript

I've searched through StackOverflow for what I regard as a basic issue, but I could not find any relevant threads. Mainly because I feel like I am searching for the wrong keywords.
I would like to know how the summarize the next bit into as few lines of code as possible. When you click on 'link-#', it loads the content from the hidden div 'more-#' (where the # in more could be any number, but is the same as the number in link-#.) Right now I have this:
jQuery("#link-1").click(function(){
jQuery('#more').hide().html($('#more-1').html()).fadeIn(400)
});
jQuery("#link-2").click(function(){
jQuery('#more').hide().html($('#more-2').html()).fadeIn(400)
});
jQuery("#link-3").click(function(){
jQuery('#more').hide().html($('#more-3').html()).fadeIn(400)
});
etc.
I assume it should be something like below, but obviously it's not the correct way.
jQuery("#link" + NUMBER ).click(function(){
jQuery('#more').hide().html($('#more-' + this.NUMBER).html()).fadeIn(400)
});
I bet you guys know exactly how to deal with this! Thank you for your help.
Best regards,
Thomas

A preferable approach is to group these items by giving them the same class, and use a data-* attribute to identify the associated element:
jQuery(function() {
jQuery(".show-more").click(function() {
var target = $(this).data('target');
jQuery('#more').hide().html($(target).html()).fadeIn(400);
});
});
#moreItems {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
Show More 1
Show More 2
Show More 3
<div id="more"></div>
<div id="moreItems">
<div id="more-1">Here are the details 1</div>
<div id="more-2">Here are the details 2</div>
<div id="more-3">Here are the details 3</div>
</div>

Give them all the same class name and then add the attribute "data-num" and then:
jQuery(".className").click(function () {
var $this = $(this);
var html = jQuery('#more' + $this.attr('data-num')).html();
jQuery('#more').hide().html(html);
});
Example HTML:
<a class='className' data-num='1'>Link</a>
<div id='more1'></div>
<div id='more'></div>

Related

Append a div outside of the input parent

Im fairly new to javascript and I just can't figure this out despite my attempt in researching. How do I track the change of a input within a div and trigger an append to an outside div? My code goes as follow:
Append h3 with "Pending" once ".image-value" input has a change in value
<!-- APPEND <h3> -->
<h3>Best Overall Costume<div class="pending">Pending</div></h3>
<div>
<div class="select-form">
<img src="images/vote.jpg" data-value="image_value">
<img src="images/vote.jpg" data-value="image_value2">
<img src="images/vote.jpg" data-value="image_value3">
<img src="images/vote.jpg" data-value="image_value4">
<img src="images/vote.jpg" data-value="image_value5">
<!-- Track the change of this input -->
<input type="hidden" class="image-value" name="selected_image" value="">
</div>
</div>
I tried this:
function changeStatus(statusValue) {
$("input",".select-form").val(statusValue).trigger("change");
}
$("input",".select-form").change(function(){
if (!$(this).val()){
$("<div class='pending'>Pending</div>").appendTo($("h3").prev($(this)));
}
});
But that didn't seem to work. Any ideas?
place an empty div where you want your new div and give it an id i.e(<div id='myDiv'><div>) and then append what you want like this.
$( "#myDiv" ).append( "<div class='pending'>Pending</div>" );
You can also check Append Explained
for more explanations.
Thanks.
I've done a couple things here... First, I'm not sure why you had it all in a named function. When you're using event listeners that often isn't necessary.
Then, I don't know what the val check was for, so I reversed it.
Finally, I'm using one(), which only runs once. This case seemed to call for that.
$('.select-form').one('change', 'input', function () {
if ( $(this).val() ) { alert('asdgf');
$("<div class='pending'>Pending</div>")
.appendTo($(this).parent().prev('h3'));
}
});
Fiddle
try this:
$("input",".select-form").on("change", function(){
var $this = $(this);
if (!$this.val()){
var elem = $('<h3>Best Overall Costume<div class="pending">Pending</div></h3>');
$this.parent().parent().before(elem);
}
});
you can also place a check, that if the pending div is already added, not to add it again.
Of course this solution assumes that there are no other nested divs between the target div(before which you want to append) and the input control

Get part of CSS class as string?

Say I had the following 4 divs:
<div class="mine-banana"></div>
<div class="mine-grape"></div>
<div class="mine-apple"></div>
<div class="orange"></div>
I've discovered I can use the following JQuery selector to get the 3 "mine" divs, but I can't quite figure out how to return all the fruits that are "mine" :)
$('[class*=" mine-"]').each(function() {
var fruit = $(this).????
});
DEMO
The best way to accomplish that is to refactor your html, as #Ian pointed it out, for example :
<div class="mine" data-mine-fruit="banana"></div>
<div class="mine" data-mine-fruit="grape"></div>
<div class="mine" data-mine-fruit="apple"></div>
<div class="orange"></div>
The JS code is straightforward now :
var fruits = $('.mine').map(function () {
return $(this).attr('data-mine-fruit')
});
If you still want to use your current code, here is a regex-based code
var fruits = []
$('[class*=" mine-"], [class^="mine-"]').each(function() {
fruits.push( this.className.match(/[^a-z0-9_-]?mine-([0-9a-z_-]+)/i)[1] );
})
which really works

How do I apply jQuery's slideToggle() to $(this) and do the opposite to all other elements?

What I'd like to do is have all elements of class collapsible_list not displayed by default (with one exception... see below*), and then toggle their display when their parent <div class="tab_box"> is clicked. During the same click, I'd also like for every other element of class collapsible_list to be hidden so that only one of them is expanded at any given time.
*Furthermore, when the page initially loads I'd also like to check to see if an element of collapsible_list has a child a element whose class is activelink, and if there is one then I'd like that link's parent collapsible_list element to be the one that's expanded by default.
Here's some sample html code:
<style>
.collapsible_list {
display: none;
}
.collapsible_list.active {
display: block;
}
</style>
<div id="sidebar">
<div class="tab_box">
<div class="collapsible_tab">2014</div>
<div class="collapsible_list panel-2014">
1
2
3
</div>
</div>
<div class="tab_box">
<div class="collapsible_tab">2013</div>
<div class="collapsible_list panel-2013">
<a class="activelink" href="/2013/1">1</a>
2
3
</div>
</div>
</div>
And here's where I'm currently at with the javascript (although I've tried a bunch of different ways and none have worked like I'd like them to):
$(document).ready(function() {
// This looks redundant to me but I'm not sure how else to go about it.
$(".collapsible_list").children("a.activelink").parent(".collapsible_list:not(.active)").addClass("active");
$(".tab_box").click(function() {
$(this).children(".collapsible_list").toggleClass("active").slideToggle("slow", function() {
$(".collapsible_list.active:not(this)").each(function() {
$(this).slideToggle("slow");
});
});
});
});
I hope that's not too confusing, but if it is then feel free to let me know. Any help is much appreciated.
Since you have a dom element reference that needs to be excluded use .not() instead of the :not() selector
jQuery(function ($) {
// This looks redundant to me but I'm not sure how else to go about it.
$(".collapsible_list").children("a.activelink").parent(".collapsible_list:not(.active)").addClass("active").show();
$(".tab_box").click(function () {
var $target = $(this).children(".collapsible_list").toggleClass("active").stop(true).slideToggle("slow");
//slidup others
$(".collapsible_list.active").not($target).stop(true).slideUp("slow").removeClass('active');
});
});
Also, instead of using the slide callback do it directly in the callback so that both the animations can run simultaniously
Also remove the css rule .collapsible_list.active as the display is controlled by animations(slide)
Try This.
$('.collapsible_tab a').on('click', function(e){
e.preventDefault();
$('.collapsible_list').removeClass('active')
$(this).parent().next('.collapsible_list').toggleClass('active');
});
Fiddle Demo
I think your code would be less complicated if you simply remembered the previously opened list:
jQuery(function($) {
// remember current list and make it visible
var $current = $('.collapsible_list:has(.activelink)').show();
$(".tab_box").on('click', function() {
var $previous = $current;
// open new list
$current = $('.collapsible_list', this)
.slideToggle("slow", function() {
// and slide out the previous
$previous.slideToggle('slow');
});
});
});
Demo

how to repeat same Javascript code over multiple html elements

Note: Changed code so that images and texts are links.
Basically, I have 3 pictures all with the same class, different ID. I have a javascript code which I want to apply to all three pictures, except, the code needs to be SLIGHTLY different depending on the picture. Here is the html:
<div class=column1of4>
<img src="images/actual.jpg" id="first">
<div id="firsttext" class="spanlink"><p>lots of text</p></div>
</div>
<div class=column1of4>
<img src="images/fake.jpg" id="second">
<div id="moretext" class="spanlink"><p>more text</p></div>
</div>
<div class=column1of4>
<img src="images/real.jpg" id="eighth">
<div id="evenmoretext" class="spanlink"><p>even more text</p></div>
</div>
Here is the Javascript for the id="firsttext":
$('#firstextt').hide();
$('#first, #firsttext').hover(function(){
//in
$('#firsttext').show();
},function(){
//out
$('#firsttext').hide();
});
So when a user hovers over #first, #firsttext will appear. Then, I want it so that when a user hovers over #second, #moretext should appear, etc.
I've done programming in Python, I created a sudo code and basically it is this.
text = [#firsttext, #moretext, #evenmoretext]
picture = [#first, #second, #eighth]
for number in range.len(text) //over here, basically find out how many elements are in text
$('text[number]').hide();
$('text[number], picture[number]').hover(function(){
//in
$('text[number]').show();
},function(){
//out
$('text[number]').hide();
});
The syntax is probably way off, but that's just the sudo code. Can anyone help me make the actual Javascript code for it?
try this
$(".column1of4").hover(function(){
$(".spanlink").hide();
$(this).find(".spanlink").show();
});
Why not
$('.spanlink').hide();
$('.column1of4').hover(
function() {
// in
$(this).children('.spanlink').show();
},
function() {
// out
$(this).children('.spanlink').hide();
}
);
It doesn't even need the ids.
You can do it :
$('.column1of4').click(function(){
$(this); // the current object
$(this).children('img'); // img in the current object
});
or a loop :
$('.column1of4').each(function(){
...
});
Dont use Id as $('#id') for multiple events, use a .class or an [attribute] do this.
If you're using jQuery, this is quite easy to accomplish:
$('.column1of4 .spanlink').hide();
$('.column1of4 img').mouseenter(function(e){
e.stopPropagation();
$(this).parent().find('.spanlink').show();
});
$('.column1of4 img').mouseleave(function(e){
e.stopPropagation();
$(this).parent().find('.spanlink').hide();
});
Depending on your markup structure, you could use DOM traversing functions like .filter(), .find(), .next() to get to your selected node.
$(".column1of4").hover(function(){
$(".spanlink").hide();
$(this).find(".spanlink, img").show();
});
So, the way you would do this, given your html would look like:
$('.column1of4').on('mouseenter mouseleave', 'img, .spanlink', function(ev) {
$(ev.delegateTarget).find('.spanlink').toggle(ev.type === 'mouseenter');
}).find('.spanlink').hide();
But building on what you have:
var text = ['#firsttext', '#moretext', '#evenmoretext'];
var picture = ['#first', '#second', '#third'];
This is a traditional loop using a closure (it's better to define the function outside of the loop, but I'm going to leave it there for this):
// You could also do var length = text.length and replace the "3"
for ( var i = 0; i < 3; ++i ) {
// create a closure so that i isn't incremented when the event happens.
(function(i) {
$(text[i]).hide();
$([text[i], picture[i]].join(',')).hover(function() {
$(text[i]).show();
}, function() {
$(text[i]).hide();
});
})(i);
}
And the following is using $.each to iterate over the group.
$.each(text, function(i) {
$(text[i]).hide();
$([text[i], picture[i]].join(', ')).hover(function() {
$(text[i]).show();
}, function() {
$(text[i]).hide();
});
});
Here's a fiddle with all three versions. Just uncomment the one you want to test and give it a go.
I moved the image inside the div and used this code, a working example:
$('.column1of4').each(function(){
$('div', $(this)).each(function(){
$(this).hover(
function(){
//in
$('img', $(this)).show();
},
function(){
//out
$('img', $(this)).hide();
});
});
});
The general idea is 1) use a selector that isn't an ID so I can iterate over several elements without worrying if future elements will be added later 2) locate the div to hide/show based on location relational to $(this) (will only work if you repeat this structure in your markup) 3) move the image tag inside the div (if you don't, then the hover gets a little spazzy because the positioned is changed when the image is shown, therefore affecting whether the cursor is inside the div or not.
EDIT
Updated fiddle for additional requirements (see comments).

How to implement multiple tinyscrollbars from a class?

I'm trying to implement multiple scrollbars with the plugin Tinyscrollabr.js
http://baijs.nl/tinyscrollbar/
To implement the scrollbars, i use a function scrollify like in this article :
http://www.eccesignum.org/blog/making-tinyscrollbarjs-easier-to-implement
HTML :
<ul id="myList">
<li id="scrollbar1" class="col">
<h2>Title 01</h2>
<div class="scrollBox"><!--Scrollable Content here--></div>
</li>
<li id="scrollbar2 class="col">
<h2>Title 02</h2>
<div class="scrollBox"><!--Scrollable Content here--></div>
</li>
<li id="scrollbar3 class="col">
<h2>Title 03</h2>
<div class="scrollBox"><!--Scrollable Content here--></div>
</li>
</ul>
Javascript :
function scrollify(element,options) { // '#element', {list:of,key:values}
var opt = options || {}
$(element).children().wrapAll('<div class="viewport"><div class="overview"></div></div>');
$(element).prepend('<div class="scrollbar"><div class="track"><div class="thumb"><div class="end"></div></div></div></div>');
$(element).tinyscrollbar(options);}
$scrollbar1 = $('#scrollbar1 .scrollBox') ;
$scrollbar2 = $('#scrollbar2 .scrollBox');
$scrollbar3 = $('#scrollbar3 .scrollBox');
$scrollbar4 = $('#scrollbar4 .scrollBox');
$(function() {
scrollify($scrollbar1);
scrollify($scrollbar2);
scrollify($scrollbar3);
scrollify($scrollbar4);
})
I would to make this more simple.
For example, i would to be able to make this :
$(function() {
scrollify('.scrollBox');
})
But tinyscrollbar need an id. With a class, it's load the first scrollbar and not the others. Firebug return this error message "f.obj[0] is undefined"
Sorry if my question is stupid, but how can I do for applying tinyscrollbar to a list of elements with a class ?
And then, after some actions how to update all this scrollbars with the function $allScrollbars.tinyscrollbar_update();
Thanks for help, I'm just beginning with javascript and i'm trying to learn.
I would count the number of elements with the class:
var scrollCount = $(".scrollbox").size();
Then use an iterating loop to call each of your IDs:
for (i=0; i<5; i++) {
scrollify($('#scrollbar' + i));
}
Also I would recommend using DIVs instead of the list setup you have, use the example from the link you shared as a starting point :)
Thanks KneeSkrap3r for your answer. It's a good solution to make this but i'm trying to do something in the case i' don't know the numbers of element to scroll.
I think I've found with something like this (it's a part from the first jquery plugin i'm trying to do ) where $el is all elemnts with the class"scrollbox".
$el.each(function(index)
{
var $scrolls = $(this);
function scrollify(element,options)
{ // '#element', {list:of,key:values}
var opt = options || {}
$(element).children().wrapAll('<div class="viewport"><div class="overview"></div></div>');
$(element).prepend('<div class="scrollbar"><div class="track"><div class="thumb"><div class="end"></div></div></div></div>');
$(element).tinyscrollbar(options);
}
scrollify($scrolls);
// Update heights
$(window).resize(function()
{ $scrolls.tinyscrollbar_update('relative');
});
})
Like this, it's seems to work but i don't know if i'm using good practice of javascript.
For the Html markup, I told the li elements for div, it's better for the semantic.
Thanks for tips ;-)

Categories

Resources