Vec10
Vec10

Reputation: 49

jquery works for only one section?

I've been fooling around with some jquery and trying to make a button show content when clicked, and hide it when clicked again.

The problem I'm having is that only the first button works the way I want it. The others don't work at all.

You can take a look at my JSFiddle: http://jsfiddle.net/jd367bbv/

$(document).ready(function () {
    $(".comments").hide();

    var toggled = false;

    $("#comment-display").click(function () {
        if (toggled) {
            $(this).next().slideToggle(100);
            toggled = false;
            $(this).text("Show Comments");
        } else {
            $(this).next().slideToggle(100);
            toggled = true;
            $(this).text("Hide Comments");
        }
    });
});

Am I missing something?

This method works when I do it with H1 headers: http://jsfiddle.net/98sLxLc8/

I just can't seem to understand why it won't work with my other jquery code.

I'm quite new to javascript, let alone jquery and I'm just trying out new things.

Thanks!

Upvotes: 0

Views: 263

Answers (4)

vol7ron
vol7ron

Reputation: 42109

Fiddle

HTML

<button class="comment-display">Show Comments</button>
<div class="comments"><!-- unchanged --></div>
<button class="comment-display">Show Comments</button>
<div class="comments"><!-- unchanged --></div>

JavaScript

$(document).ready(function () {
    $(".comments").hide();

    $(".comment-display").click(function () {
        var $this = $(this);
        $this.next().slideToggle(100);

        if ($this.data('toggled')) {
            $this.data('toggled',false);
            $this.text("Show Comments");
        } else {
            $this.data('toggled',true);
            $this.text("Hide Comments");
        }
    });
});

Explanation

  • instead of using id, I made comment-display a class in the HTML and updated jQuery selector to reflect this; as others have stated, you can only have one ID per page (much like you would not want someone else to have the same Social Security # as you). The method works with your Heading example because you are selecting by element name; there can be multiple elements per page, but again only one value for ID, regardless of element
  • cache a jQuery object when used more than once, in this case I've cache'd $(this); from here on out I'll be using $this to reference that object
  • $this.next().slideToggle(100) is being performed regardless if the condition passes or fails, you can reduce duplication and pull it out of the blocks. Note: the only way this would have not executed is if there was a JS error prior to the block being accessed (such as in the condition), but it's almost safe to assume this would not happen
  • IMPORTANT: the variable toggled is used by both elements; notice what happens when you click one button and then click the other (the wording becomes out of sync with the state). To avoid this you should use either classes or data-* attributes to localize the toggled state to the element. I used data-* in the above because it was easier to demonstrate how it should work and a little bit cleaner to work with

Pro-Move

$(document).ready(function() {
    $(".comments").hide();

    $(".comment-display").click(function() {
        var $this   = $(this),
            toggled = !!$this.data('toggled');

        $this.next().slideToggle(100).end()
             .data( 'toggled', !toggled )
             .text( (toggled?'Show':'Hide')+' Comments' );
     });
});

This is a more condensed version of the above. Notice that several pro-moves are used:

  • exclamation prefix operator (!!) is used twice to get a boolean. This is because the data-toggled value is undefined by default. undefined is falsy, so using one exclamation point will make it true, but we want the original value, so we use two-eclamation point, making it false. This may not be needed here, but is good exposure, in case you ever see it again in the future
  • end() is used in the jQuery because next() was called. next() returns a chain of elements that follow the current selector, but in this case we want to perform the slide action and then perform actions on the original object ($this), not those returned by the call to next. To do this, end() is used. Appropriately named, it ends that chain and goes up to the previous selector, this leads us to be able to update the data() and text() as part of the same statement, reducing more code -- Note: you wouldn't want to chain too many commands here. That is because it may become harder to follow, but these 3 make logical sense (perform action, update view and model)
  • the if-statement wasn't doing too much, so we can use the ternary operator (?:) inside the text() method, again to reduce the amount of syntax used and [hopefully] improve readability and comprehension

I'm sure others could latch on and make this even better, or reduce it even further; but this should be enough to gain a new perspective on how a library like jQuery can be utilized.

Upvotes: 2

Wael Showair
Wael Showair

Reputation: 3102

First of all, you have the same id for the two buttons which leads to selecting the first button always. Accordingly you will need to target both buttons using their html attribute instead of specific id. You can do something like:

$(document).ready(function () {
    $(".comments").hide();

    var toggled = false;

    $("button").click(function () {
        if (toggled) {
            $(this).next().slideToggle(100);
            toggled = false;
            $(this).text("Show Comments");
        } else {
            $(this).next().slideToggle(100);
            toggled = true;
            $(this).text("Hide Comments");
        }
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="comment-display">Show Comments</button>
<div class="comments">
    <div class="comment">
        <div class="comment-author">Author</div>
        <div class="comment-content">Comment Content</div>
    </div>
    <div class="comment">
        <div class="comment-author">Author</div>
        <div class="comment-content">Comment Content</div>
    </div>
    <div class="comment">
        <div class="comment-author">Author</div>
        <div class="comment-content">Comment Content</div>
    </div>
</div>
<hr>
<button id="comment-display-2">Show Comments</button>
<div class="comments">
    <div class="comment">
        <div class="comment-author">Author</div>
        <div class="comment-content">Comment Content</div>
    </div>
    <div class="comment">
        <div class="comment-author">Author</div>
        <div class="comment-content">Comment Content</div>
    </div>
    <div class="comment">
        <div class="comment-author">Author</div>
        <div class="comment-content">Comment Content</div>
    </div>
</div>

You example with header was working because you were targeting all header tags not only a specific header as you did with the buttons. Hopefully, this will help you.

Upvotes: 1

Shaun K.
Shaun K.

Reputation: 391

ID values must be unique on a page. You have two buttons with the same ID. Either give each button a unique ID, or use a class instead, like this:

$(document).ready(function () {
    $(".comments").hide();

    var toggled = false;

    $(".comment-display").click(function () {
        if (toggled) {
            $(this).next().slideToggle(100);
            toggled = false;
            $(this).text("Show Comments");
        } else {
            $(this).next().slideToggle(100);
            toggled = true;
            $(this).text("Hide Comments");
        }
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="comment-display">Show Comments</button>
<div class="comments">
    <div class="comment">
        <div class="comment-author">Author</div>
        <div class="comment-content">Comment Content</div>
    </div>
    <div class="comment">
        <div class="comment-author">Author</div>
        <div class="comment-content">Comment Content</div>
    </div>
    <div class="comment">
        <div class="comment-author">Author</div>
        <div class="comment-content">Comment Content</div>
    </div>
</div>
<hr>
<button class="comment-display">Show Comments</button>
<div class="comments">
    <div class="comment">
        <div class="comment-author">Author</div>
        <div class="comment-content">Comment Content</div>
    </div>
    <div class="comment">
        <div class="comment-author">Author</div>
        <div class="comment-content">Comment Content</div>
    </div>
    <div class="comment">
        <div class="comment-author">Author</div>
        <div class="comment-content">Comment Content</div>
    </div>
</div>

Upvotes: 1

Robin Carlo Catacutan
Robin Carlo Catacutan

Reputation: 13679

It's because you are using the same Id on two elements. So I made the bottom button id to comment-display-bottom instead.

Then target two elements on click event $("#comment-display, #comment-display-bottom")

$(document).ready(function () {
    $(".comments").hide();

    var toggled = false;

    $("#comment-display, #comment-display-bottom").click(function () {
        if (toggled) {
            $(this).next().slideToggle(100);
            toggled = false;
            $(this).text("Show Comments");
        } else {
            $(this).next().slideToggle(100);
            toggled = true;
            $(this).text("Hide Comments");
        }
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="comment-display">Show Comments</button>
<div class="comments">
    <div class="comment">
        <div class="comment-author">Author</div>
        <div class="comment-content">Comment Content</div>
    </div>
    <div class="comment">
        <div class="comment-author">Author</div>
        <div class="comment-content">Comment Content</div>
    </div>
    <div class="comment">
        <div class="comment-author">Author</div>
        <div class="comment-content">Comment Content</div>
    </div>
</div>
<hr>
<button id="comment-display-bottom">Show Comments</button>
<div class="comments">
    <div class="comment">
        <div class="comment-author">Author</div>
        <div class="comment-content">Comment Content</div>
    </div>
    <div class="comment">
        <div class="comment-author">Author</div>
        <div class="comment-content">Comment Content</div>
    </div>
    <div class="comment">
        <div class="comment-author">Author</div>
        <div class="comment-content">Comment Content</div>
    </div>
</div>

Upvotes: 1

Related Questions