Help with jquery show/hide function - how to toggle button text

I’m using JQuery to hide a map on the page and then insert a show/hide text link that, when clicked will reveal the <span> that contains the map. I want to toggle the text between show and hide depending on whether the map section is visible or not.

I’ve got the show/hide function working and the text is initially set to show when the map is hidden. Clicking on the text will show the map and change the text to hide.

I’m having problems changing the text back to ‘show’ if the user clicks on the hide map link.

The example is on this page:
http://www.sutherlandshire.nsw.gov.au/Library/Whats_On/test_event_-_martin

here is the html of the section in question

<p class="event-where">
    <span class="where">Where:</span> Sutherland Library<br>
    30-36 Belmont Street, Sutherland NSW 2232
    <span class="event-map">
	<iframe width="440" scrolling="no" height="300" src="http://maps.google.com/maps?..." ></iframe>
    </span><!-- event-map -->
</p>

Here is the JQuery code I’ve written so far.

//hide the map by default
  $('.event-map').hide();

  //Add the button to toggle the map
  $('<span id="toggle-map">Show Map</span>').insertBefore('.event-map');

  //toggle the display by clicking on button
  $('#toggle-map').click(function () {
    $('.event-map').slideToggle('fast');
    if ($('#toggle-map').is(':visible')) {
      $(this).text('Hide Map');
    } else {
      $(this).text('Show Map');
    }
  });

I’m not sure why this doesn’t work. Any suggestions as to how I can get the text to change back on the second click or an explanation of why this code doesn’t work?

thanks,
Martin

Hi boycetrus and welcome to SitePoint,

The reason as to why your above code isn’t working correctly is due to how you have setup the element for the toggle event, instead of targeting specific elements by their class name or ID you really should be using some built into jQuery methods which help with situations like this. See the below for a version of the above code that should work fine.

$('.event-map').each(function() {
    // Hide the map by default
    $(this).hide();
    
    // Add a button before the map to toggle it
    $('<span />', {
        'class' : 'toggle-map',
        html    : 'Show Map'
    }).on('click', function() {
        // Cache the jQuery object for the map
        var $map = $(this).next('.event-map');
        
        // Toggle the map
        $map.slideToggle();
        
        // Change the text on the toggle button
        $(this).text(($map.is(':visible') ? 'Show' : 'Hide') + ' Map');
    }).insertBefore(this);
});

Thanks for that Chris.
I’m relatively new to jquery (and fairly useless at javascript), however I’ve worked my way through most of your code above and, although there are a couple of new bits to me in there, I understand what’s going on for the most part.

I am having a bit of trouble deciphering what’s actually happening with the line that swaps the text of the button based on the visibility of the $map object, ie.

$(this).text(($map.is(':visible') ? 'Show' : 'Hide') + ' Map');

I can see that $(this).text(…) is setting the text of the button
I gather that …‘Show’ : ‘Hide’) + ’ Map’) is concatenating show or hide with map to create the text string.

I’m just not sure how the test for whether $map (.event-map) is visible works. That is, this bit ($map.is(‘:visible’) ? ‘Show’ : ‘Hide’)

If anyone can explain exactly what’s happening in this snippet of code I would be very grateful.

cheers,
Martin

Hi again,
Never mind about the follow up. I just went digging around a bit more and I think I’ve worked it out.

The ? is a conditional operator so if $map.is(‘:visible’) returns true then use Show, otherwise use Hide. I can see how the conditional operator can be used as an alternative to if/else.

thanks for your help.
Martin

That’s correct, for future reference just so you know it’s called a ternary operator which you can call a conditional operator but that would get confusing as if/else statements also have conditional operators aka && (and) and || (or).

Got it!
Thanks Chris.

Martin

Here’s how they break down.

The following code is an example of what the ternary operator deals with:


if (member === true) {
    fee = 2;
} else {
    fee = 10;
}

With the ternary operator, you can handle the above situation as a single line, without losing the ability to easily understand what is going on.


fee = (member === true) ? 2 : 10;

The && operator is the AND operator; also called a guard condition. If the first part is falsy (null, undefined, 0, empty string, false, etc…) then the test fails, and the next part isn’t even processed. This means that you can use it to protect against situations that may cause a syntax error.

Normally code to do that would be:


if (element) {
    if (element.nodeType === 1) {
        if (element.nodeName === 'A') {
            // do stuff with the anchor element
        }
    }
}

Whereas by making good use of the && operator, the above can be done just as easily with:


if (element && element.nodeType === 1 && element.nodeName === 'A') {
    // do stuff with the anchor element
}

You commonly see the guard condition being used when dealing with objects, so that you don’t inadvertently attempt to access a property or a method that may not exist.

The || operator is the OR operator, which is also be used as a default operator. If the first part is truthy, JavaScript doesn’t carry on to process the rest of the statement.

So you might set a default value for something as:


var amount = 0;
if (parseFloat(total)) {
    amount = parseFloat(total);
}

By making good use of the default operator, we can easily assign the parsed value, and default to a certain value if it doesn’t parse to a meaningful value.


var amount = parseFloat(total) || 0;

You commonly see the default operator being used when something may not exist, so that you can provide a default meaningful value for it instead.