Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 8 years ago.
Improve this question
I'm a bit new to javascript and jquery, and I have some troubles doing what I want in a "nice" way.
I have a HTML web page like this:
<div class="list-group">
All
Foo
Bar
FooBar
</div>
<div class="row">
<div class="category-0">element 1</div>
<div class="category-1">element 1</div>
<div class="category-1">element 1</div>
<div class="category-0">element 1</div>
<div class="category-2">element 1</div>
<div class="category-0">element 1</div>
<div class="category-2">element 1</div>
</div>
I would like to add some kind of "filter", where if you click on a certain category link, all elements from other categories will disappear.
I managed to do it by adding a class to my css called invis with "display:none", and then wrote this:
$( ".list-group-item" ).click(function() {
$(".list-group-item").removeClass('active');
$( this ).toggleClass("active");
var test = "." + event.target.id;
$(".category-0").addClass('invis');
$(".category-1").addClass('invis');
$(".category-2").addClass('invis');
if (test == ".category-0")
$(".category-0").removeClass('invis');
if (test == ".category-1")
$(".category-1").removeClass('invis');
if (test == ".category-2")
$(".category-2").removeClass('invis');
if (test == ".category-all") {
$(".category-0").removeClass('invis');
$(".category-1").removeClass('invis');
$(".category-2").removeClass('invis');
}
});
This does the job, but I'd like to find a "cleaner" way of doing it. How can I improve it?
Thanks !
One way to do it using jQuery would be to hide all of the <div>s when a filter control is clicked, then unhide the specific ones that you want to show.
This way you won't need your extra invis class.
you will notice the "^=" symbol in the below code it simply is a selector that literally means "starts with".
$('a[id^="category"]').click(function() {
// when an <a> element is click THAT has an ID that starts with "category" ...
$('div[class^="category"]').hide();
// hide every <div> that's ID starts with "category" ...
$('div.' + this.id).show();
// re-show every <div> that's CLASS matches the original <a>'s ID ...
});
$('a[id="show-all"]').click(function() {
// if the "all" is clicked, show them ALL again.
$('div[class^="category"]').show();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="list-group">
All
Foo
Bar
FooBar
</div>
<div class="row">
<div class="category-0">Foo</div>
<div class="category-1">Bar</div>
<div class="category-1">Bar</div>
<div class="category-0">Foo</div>
<div class="category-2">FooBar</div>
<div class="category-0">Foo</div>
<div class="category-2">FooBar</div>
</div>
Hide all elements with class "row" and then un-hide all elements with class [id of what was clicked] within class "row".
$('.list-group-item').click(function(event) {
$('.row').addClass('invis');
$('.row.' + event.target.id).removeClass('invis');
});
By simply adding to all your categories the .category-all you've done half-job.
Now you can control the id>>>class relations much easily.
jsBin demo
If you need to always have at least one category visible it's quite simple:
var $btns = $(".list-group-item");
var $ctgs = $("[class^='category-']");
$ctgs.addClass("category-all"); // Job done! :D :D
$btns.click(function(e) {
$ctgs.hide(); // Hide all
$("."+this.id).show(); // Show realated
});
Otherwise, The code below will allow you to have any combination you desire
And even hide/toggle the active ones:
jsBin demo
var $btns = $(".list-group-item");
var $ctgs = $("[class^='category-']");
$ctgs.addClass("category-all"); // Job done! :D :D
$btns.click(function(e) {
$ctgs.not("."+this.id).hide(); // Hide all (not this...)
$("."+this.id).toggle( $(this).hasClass("active") ); // Toggle realated
});
Disclaimer: not tested.
$('.list-group-item').click(function() {
$('.list-group-item').removeClass('active');
$(this).addClass('active');
var id = $(this).attr('id');
if(id == 'category-all') {
$('div.row > div').show();
} else {
$('div.row > div.' + id).show();
$('div.row > div:not(.' + id + ')').hide();
}
});
Here's another version. Added color coding for visibility.
*Edit updated to actually have the right behavior.
http://codepen.io/anon/pen/NPrGJp
$( ".list-group-item" ).click(function() {
$('.active').removeClass('active');
$(this).addClass('active');
$('.row > div').show();
$('.' + $(this).attr('id')).hide();
});
Related
So I have this thing where I need one div to be shown at any one time depending on the button clicked. I found this great fiddle which is almost perfect except for the fact that it doesn't show when one link is selected. I'd like to have it so that the link that's selected can have a sort of active class or look different from the other links. Is that possible? I've been looking through questions and I can't really find an answer for this.
If anyone's interested, I'm using it for this (but the code is really messed up, sorry). (I'd also like to change the filter buttons on the top row to reset and filter all the images, but am aware that's a different question. Still any help would be appreciated!)
html
<div id="linkwrapper">
<a id="link1" href="#">link1</a><br/>
<a id="link2" href="#">link2</a><br/>
<a id="link3" href="#">link3</a>
</div>
<div id="infocontent">
<div id="link1content">Information about 1.</div>
<div id="link2content">Information about 2.</div>
<div id="link3content">Information about 3.</div>
</div>
jquery
$(document).ready(function(){
$("#infocontent").hide();
$("#infocontent div").hide();
$('#linkwrapper a[id]').click(function(){
var vsubmen = this.id +"content";
if( $("#infocontent").is(":visible") == false ) {
$("#" + vsubmen).show('fast',function() {
$("#infocontent").slideDown();
});
} else if ( $("#" + vsubmen).is(":visible") == false ) {
$("#infocontent").slideUp('slow',function(){
$("#infocontent div").hide();
$("#" + vsubmen).show();
$("#infocontent").slideDown('slow');
});
} else {
$("#infocontent").slideUp('slow',function(){
$("#infocontent div").hide();
});
}
return false;
});
});
You can simplify that fiddle like this:
$('a[id^=link]').click(function(){
$('a[id^=link]').removeClass('meactive');
$(this).addClass('meactive');
$('#infocontent>div').slideUp();
var tmp = this.id;
$('#'+tmp+'content').slideDown();
}); //end a.click
jsFiddle Demo
Notes:
(1) $('a[id^=link]') -- grabs all a elements with a ID that starts with link
(2) $('#' +tmp+ 'content') -- builds selectors like: $('#link3content)`
What I am trying to do is use 3 clickable divs as switches which when clicked change the background of an element (using the attribute data-image-src) which is the grandparent of the div.
Heres my HTML:
<header class="header-index locations-header col-lg-12 clearfix " data-parallax="scroll" data-image-src="images/2V1C8599.jpg">
<section class="locations-switcher col-md-12 clearfix">
<div class="first-switch col-sm-4"><h2>div one</h2></div>
<div class="second-switch col-sm-4"><h2>div two</h2></div>
<div class="third-switch col-sm-4"><h2>div three</h2></div>
</section>
</header>
and my jQuery:
$(".locations-switcher div").click( function() {
if($("div", this).attr('class') === "first-switch") {
$(".locations-header").attr( "data-image-src", "../images/IMG_4519_.jpg)" );
} else if( $("div", this).attr('class') === "second-switch") {
$(".locations-header").attr( "data-image-src", "../images/2V1C8599.jpg" );
} else if ($("div", this).attr('class') === "third-switch") {
$(".locations-header").attr( "data-image-src", "../images/UBC-Interior.jpg" );
}
});
Any clue to why its not working. I'm still fairly new to javascript and jQuery. Any help would be really great.
use:
if($(this).hasClass('first-switch')){
instead of:
if($("div", this).attr('class') === "first-switch") {
I think $('div', this) will look for CHILD divs, you want to look at the element you already found.
because there are other classes on the element, .attr('class') will return the whole string, .hasClass() will check the whole list
you have an extra parentheses in the first source string
depending on how data-image-src is used you might have to trigger something else to redraw it. I usually manually set .css('background-image', 'url(' + srcString + ')')
I am trying to select all following elements of an element I choose. They don't necessarily have to be direct siblings of my chosen Element, so .nextAll() won't work.
Here's an example:
<div class="scope">
<div> 1 </div>
<div> 2 </div>
<div> 3 </div>
<div> 4 </div>
</div>
NOT THIS
My element is a[href="2"], so I want to select a[href="3"] and a[href="4"], but not a[href="x"] because it's not in my scope.
I found this, but it only fetches one follower, but I need all of them.
I just wrote this, which works great, but it seems odd to me and I am sure that there have to be better solutions than this one:
var $two = $('a[href="2"]');
var selection = [];
var comes_after_2 = false;
$two.closest('.scope').find('a').each(function(){
console.log(this, $two.get(0));
if(comes_after_2){
selection.push(this);
}
if(this == $two.get(0)){
comes_after_2 = true;
}
});
$(selection).css('background', 'red');
Here is a Fiddle to test it: http://jsfiddle.net/mnff40fy/1/
Please feel free to modify it, if there's a better solution. Thank you!
var $all_a = $two.closest('.scope').find('a');
// Get the position of the selected element within the set
var a_index = $all_a.index($two);
// Select all the remaining elements in the set
var $followers = $all_a.slice(a_index+1);
$followers.css('background', 'red');
DEMO
How about this?
JSFiddle
I changed the markup a little to have the href='#' so you could click each one and see how the other elements respond.
$('a').click(function(){
$('a').css('background', 'none');
var scopeDiv = $(this).closest('div.scope');
var thisIndex = $(scopeDiv).find('a').index(this);
$(scopeDiv).find('a').not(this).each(function(index){
if(index >= thisIndex)
$(this).css('background', 'red');
});
});
As an alternative, you can use .nextAll() if you modify it a bit.
In your html code, you placed the a elements as children of the div tags. In order to incorporate .nextAll() you should select for the wrapper div elements and then call .nextAll() and then select for the children a elements.
Here is what I mean.
html
<div class="scope">
<div>
1
</div>
<!-- Start Here -->
<div class="start">
2
</div>
<div>
3
</div>
<div>
4
</div>
</div>
NOT THIS
js
$( '.start' ).nextAll().children( 'a' ).css( 'background-color', 'red' );
Explanation:
I select the wrapper div with $( '.start' )
I then select all of its subsequent siblings with .nextAll()
Of those siblings, I select their children that match 'a'
I apply the css
And here is the Fiddle
I've seen various examples come close to what I am looking for, but none of it seems to describe it how I exactly want it. I am a beginner to jQuery, so explanations welcome.
I'm looking for this to toggle the innerHTML from - to +. Anyone know of a way to do this, efficiently?
jQuery/JavaScript
$(document).ready(function() {
$(".A1").click(function() {
$(".P1").toggle("slow");
$(".A1").html("+");
});
});
HTML
<div class="A1">-</div>
<h2 class="H1">Stuff</h2>
<div class="P1">
Stuffy, Stuffy, Stuffed, Stuffen', Stuffing, Good Luck Stuff
</div>
Thank you, anything relating to switching the inside text of an HTML element shall help. =)
How about adding a class that will let you know the expanded/collapsed status?
$(document).ready(function() {
$(".A1").click(function() {
var $this = $(this);
$(".P1").toggle("slow")
$this.toggleClass("expanded");
if ($this.hasClass("expanded")) {
$this.html("-");
} else {
$this.html("+");
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="A1 expanded">-</div>
<h2 class="H1">Stuff</h2>
<div class="P1">
Stuffy, Stuffy, Stuffed, Stuffen', Stuffing, Good Luck Stuff
</div>
Example: http://jsfiddle.net/sGxx4/
$(document).ready(function() {
$(".A1").click(function() {
$(".P1").toggle("slow");
$(".A1").html(($(".A1").html() === "+" ? $(".A1").html("-") : $(".A1").html("+")));
});
});
A bit of explanation: I'm setting $("#A1").html() with the product of the tertiary operator, using it to check for the current value of #A1's text. If it's a +, I set the element's text to -, otherwise, I set it to +.
However, you said "efficiently." To this end, it's important to note that if you're going to use a selector twice or more in the same function, you should store the jQuery object that results from the selector you give in a variable, so you don't have to re-run the selector each time. Here's the code with that modification:
$(document).ready(function() {
$(".A1").click(function() {
var $A1 = $(".A1");
$(".P1").toggle("slow");
$A1.html(($A1.html() === "+" ? $A1.html("-") : $A1.html("+")));
});
});
There's no way to toggle content.
You could check if the $('.P1') is visible, then changing the +/- div according to that.
Something like :
$(document).ready(function() {
$(".A1").click(function() {
$(".P1").toggle("slow", function(){
if($(this).is(':visible'))
$(".A1").html("-")
else
$(".A1").html("+")
});
});
});
Using a callback function (the second argument of the .toggle() method) to do the check will guarantee that you're checking after the animation is complete.
JsFiddle : http://jsfiddle.net/cy8uX/
more shorter version
$(document).ready(function() {
$(".A1").click(function() {
var $self = $(this);
$(".P1").toggle("slow", function ( ) {
$self.html( $self.html() == "-" ? "+" : "-");
});
})
});
Here's a way that uses class names on a parent and CSS rules and doesn't have to change the HTML content and works off a container and classes so you could have multiple ones of these in the same page with only this one piece of code:
HTML:
<div class="container expanded">
<div class="A1">
<span class="minus">-</span>
<span class="plus">+</span>
</div>
<h2 class="H1">Stuff</h2>
<div class="P1">
Stuffy, Stuffy, Stuffed, Stuffen', Stuffing, Good Luck Stuff
</div>
</div>
CSS:
.expanded .plus {display:none;}
.collapsed .minus {display: none;}
Javascript:
$(document).ready(function() {
$(".A1").click(function() {
$(this).closest(".container")
.toggleClass("expanded collapsed")
.find(".P1").slideToggle("slow");
});
});
Working demo: http://jsfiddle.net/jfriend00/MSV4U/
Suppose I have some divs which I want to allow users to switch between. I would write functions like this:
show_A = function () {$('.a').show(); $('.b').hide(); $('.c').hide();}
show_B = function () {$('.a').hide(); $('.b').show(); $('.c').hide();}
show_C = function () {$('.a').hide(); $('.b').hide(); $('.c').show();}
Then attach these functions to links or whatever. What's the best practice for abstracting out this sort of behavior? The total amount of code grows at N^2 with the number of divs, which is no good.
Give all those divs that you want to hide a common class name and then show one of those. like:
html:
<div class="a toggle">a div</div>
<div class="b toggle">b div</div>
<div class="c toggle">c div</div>
Now the js:
show_A = function () {$('.toggle').hide(); $('.a').show();}
show_B = function () {$('.toggle').hide(); $('.b').show();}
show_C = function () {$('.toggle').hide(); $('.c').show();}
The way I've handled this is before was just to hide them all then show the one (or ones) that you want visible.
Something like...
var showSingleDiv = function(klass) {
$('.container > div').hide();
$(klass).show();
};
Granted you don't want to hide every div so you'll need to setup whatever .container is with your own markup.
For each click, you could hide all the divs and then show only the one you need.
You could use a class to tag the divs involved...
<div id="a" class="collapse">...</div>
<div id="b" class="collapse">...</div>
<div id="c" class="collapse">...</div>
And use:
$(".collapse").hide();
You can do something like, by adding a common class to all those elements:
<div class="toggle">a</div>
<div class="toggle">b</div>
<div class="toggle">c</div>
$('.toggle').click(function(){
$('.toggle:visible').hide(); //Hide all visible 'toggle' div's
$(this).show(); //Show the clicked div
});
You can use the :not() selector.
show_A = function () {$('.a').show(); $('div:not(.a)').hide();}
Maybe I'm not understanding the question, but it seems like what he's wanting is something along these lines:
$('div').each().click( function(){
var cls = $(this).attr('class');
if( $("div[class*='"+cls+"']").is(':visible')){ $("div[class*='"+cls+"']").hide();}//
else{ $("div[class*='"+cls+"']").show(); }
}
);
//Disclaimer - I did not check to see if the concatenated selector works, but adapted it from a reputable blog.