fromdecay
fromdecay

Reputation: 5

Revert slide toggle button text on close

Alright, so I have the following code written for a 'read more' button. Clicking it toggles the div and changes 'read more' to 'read less'. Clicking a different one closes the other open div, and also switches the text to the appropriate wording.

HOWEVER, I can't seem to figure out how to have the text switch back to 'read more' when I click the same toggle button.

Example read more x read more y

If I click 'read more x', it toggles x's hidden div and the button becomes 'read less x'. When I click 'read less x', it toggles the div BUT remains as 'read less x' rather than reverting.

I've tried shoving the $(this).text snippet in various parts of the function but to no avail.

$(document).ready(function () {
        var content = $('.below').hide();
        $('.toggleBtn').on('click', function () {
             var $this = $(this);
			$(this).text("read less");
           $this.next('.below').slideToggle().siblings('.below').slideUp();
           $this.toggleClass('active').siblings('.toggleBtn.active').removeClass('active').text("read more");
            return false;
			});
        //register the handler to button element inside .below
        $('.below .close').on('click', function () {
            //find the ancestor .below element of the clicked button
            $(this).closest('.below').slideToggle();
        });
    });
.below {display: none;}
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js" ></script>

<div class="toggleBtn">read more x</div>
<div class="below">slideout x</div>

<div class="toggleBtn">read more y</div>
<div class="below">slideout y</div>

Upvotes: 0

Views: 340

Answers (2)

Roamer-1888
Roamer-1888

Reputation: 19288

Fromdecay, if you are interested in a different approach, here's another way to code this :

  • .promise().done(...) can be used to wait until slide animations are complete before testing .is(':visible') and setting button texts. This gives an aguably more pleasing visual effect. Testing an element's contents is bad practice.
  • The className 'active' can be discarded (unless required for styling).
  • The javascript can be free of hard-coded text strings (at least the ones that appear in the UI). The more/less texts can be defined in the HTML as data- attributes, which are used for setting the buttons' text, similar to @imtheman's answer.
  • By triggering the .toggleBtn click handler from 'close' buttons, all the good work of the click handler can be performed without the need for a named function and without duplicating any code.

Do all this and, believe it or not, the volume of code actually reduces.

$(document).ready(function () {
	$(".toggleBtn").on('click', function (e) {
		$(this).next('.below').slideToggle().siblings('.below').slideUp().andSelf().each(function() {
			var $below = $(this);
			$below.promise().done(function() {
				var $btn = $below.prev('.toggleBtn');
				$btn.text($btn.data( $below.is(':visible') ? 'less' : 'more' ));
			});
		});
	});
	$('.below .close').on('click', function (e) {
		$(this).closest('.below').prev('.toggleBtn').trigger('click');//trigger the click on the corresponding `.toggleBtn` element.
	});
});
.below {display: none;}
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js" ></script>

<div class="toggleBtn" data-more="read more x" data-less="read less x">read more x</div>
<div class="below">slideout X</div>

<div class="toggleBtn" data-more="read more y" data-less="read less y">read more y</div>
<div class="below">slideout Y</div>

<div class="toggleBtn" data-more="read more z" data-less="read less z">read more z</div>
<div class="below">slideout Z</div>

Upvotes: 0

imtheman
imtheman

Reputation: 4843

I recommend using the data attribute to store the current text, like so:

$(document).ready(function () {
        var content = $('.below').hide();
        $(".toggleBtn").each(function(){
           $(this).data("text", $(this).text()); //Save the current text() to data-text attribute
        });
        $('.toggleBtn').on('click', function () {
           var $this = $(this);
           
           if($this.text() == "read less")
              $this.text($this.data("text")); //Replace text with data-text if clicked again
           else
              $this.text("read less");
           
           $this.next('.below').slideToggle().siblings('.below').slideUp();
           $this.toggleClass('active').siblings('.toggleBtn.active').each(function(){
              $(this).text($(this).data("text")); //Replace previous open sibling text with data-text
           }).removeClass('active');
            return false;
			});
        //register the handler to button element inside .below
        $('.below .close').on('click', function () {
            //find the ancestor .below element of the clicked button
            $(this).closest('.below').slideToggle();
        });
    });
.below {display: none;}
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js" ></script>

<div class="toggleBtn">read more x</div>
<div class="below">slideout x</div>

<div class="toggleBtn">read more y</div>
<div class="below">slideout y</div>

Upvotes: 1

Related Questions