Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript

Ana Camelo
PLUS
Ana Camelo
Courses Plus Student 13,218 Points

Simplify Show/Hide jQuery code

Hello,

I'm working on some jQuery code that goes like this:

I have 11 buttons, each one for a month. When I click on any of the buttons that one should show me an specific image linked to that button.

I have already made the jQuery code work for the first 2 buttons. However, I think I'd be able to simplify it for better coding practices, but I don't know how.

The HTML is something like this:

<nav>
      <ul>
          <li class="green_button bt_1"><button>Enero</button></li>
          <li class="green_button bt_2"><button>Febrero</button></li>
          <li class="green_button"><button>Marzo</button></li>
          <li class="green_button"><button>Abril</button></li>
          <li class="green_button"><button>Mayo</button></li>
          <li class="green_button"><button>Junio</button></li>
          <li class="green_button"><button>Julio</button></li>
          <li class="green_button"><button>Agosto</button></li>
          <li class="green_button"><button>Septiembre</button></li>
          <li class="green_button"><button>Octubre</button></li>
          <li class="green_button"><button>Noviembre</button></li>

      </ul>
</nav>

<div id="jan" class="center">
    <img src="imgs/Slide_1.jpg" alt="Imagen Tenis MILO">
</div>

 <div id="feb" class="center">
    <img src="imgs/Slide_2.jpg" alt="Imagen Tenis MILO">
</div>

The jQuery I have for this is:

$("#jan img").hide(); $("#feb img").hide();

$(".bt_1").click(function() { $("#feb img").hide(); $("#jan img").toggle(); });

$(".bt_2").click(function() { $("#jan img").hide(); $("#feb img").toggle(); });

I think there must be a more accurate way for doing this, but i'm not quite sure how that can be, so I'd really appreciate any help.

Thanks a lot!!

Hey Ana,

Can you post a snapshot of your workspace in a new comment? If you don't know how to do that, check this page out: http://www.teamtreehouse.com/forum/workspace-snapshots. I have some ideas for your code, but I need to see your code to make sure I get it right. :P

4 Answers

David ODey
David ODey
11,744 Points

Nailed it! Great job man.

Teamwork is what it's all about man! :)

Also, the only reason I targeted the class "center" instead of all the images, is because we don't know if there might be other images on the page not related to the month picker buttons. If we targeted all of the images, then every single image on the page would get hidden so it's best to target a specific cluster of them.

David ODey
David ODey
11,744 Points

Here is what I would do.

  1. remove the classes from the list items and change the id's of the image containers to the text inside the button.
  2. then use some simple Jquery to store the button text in a variable when clicked, and toggle the containing div with the id of the new variable, which happens to be the same text thats inside button.

Here is the codepen, hope this helps! http://codepen.io/anon/pen/OPKOYx

<nav>
      <ul>
          <li><button>Enero</button></li>
          <li><button>Febrero</button></li>
      </ul>
</nav>

<div id="Enero" class="center">
    <img src="imgs/Slide_1.jpg" alt="Imagen Tenis MILO">
</div>

 <div id="Febrero" class="center">
    <img src="imgs/Slide_2.jpg" alt="Imagen Tenis MILO">
</div>

<!-- JQuery -->
<script>
$('img').hide();
$('button').click(function(){
var buttonCopy = $(this).text();
     $('#'+buttonCopy+' img').toggle();
});
</script>

The problem with this, though, is that when you click one month and then another month, both images are still on the screen when there should be only one, as outlined in the "Problem" statement in the Workspace snapshot. Although you are on the right track. I modified the code so that it will act accordingly.

Here is the code that works perfectly along with your suggestions:

<!DOCTYPE html>
<html>
<head>
    <title>Tenis - MILO</title>
    <link rel="stylesheet" href="css/normalize.css" type="text/css" media="screen" title="no title" charset="utf-8">
    <link rel="stylesheet" href="css/main.css" type="text/css" media="screen" title="no title" charset="utf-8">
</head>
<body>
<div id="wrapper">
    <nav>
          <ul>
              <li class="green_button"><button>Enero</button></li>
              <li class="green_button"><button>Febrero</button></li>
              <li class="green_button"><button>Marzo</button></li>
              <li class="green_button"><button>Abril</button></li>
              <li class="green_button"><button>Mayo</button></li>
              <li class="green_button"><button>Junio</button></li>
              <li class="green_button"><button>Julio</button></li>
              <li class="green_button"><button>Agosto</button></li>
              <li class="green_button"><button>Septiembre</button></li>
              <li class="green_button"><button>Octubre</button></li>
              <li class="green_button"><button>Noviembre</button></li>
          </ul>
    </nav>

    <div id="Enero" class="center">
        <img src="imgs/Slide_1.jpg" alt="Imagen Tenis MILO">
    </div>
     <div id="Febrero" class="center">
        <img src="imgs/Slide_2.jpg" alt="Imagen Tenis MILO">
    </div>
</div>
    <script src="http://code.jquery.com/jquery-1.11.0.min.js" type="text/javascript" charset="utf-8"></script>
    <script src="js/app.js" type="text/javascript" charset="utf-8"></script>
</body>
</html>

and the JavaScript

//1. Hide image
$(".center").hide();

//When click show the image
$("button").click(function() {
  //Hide all images
  $(".center").hide();
  //Only show this image we clicked on
  $("#"+$(this).text()).show();
});

Hi Ana,

Here's my attempt at it: http://codepen.io/anon/pen/emqyxJ

The html setup is minimal -

  • The div's need a class that no other element on the page will have. No id's are needed.
  • The li's only need classes for styling purposes.
  • The div's do need to be in the same order as the buttons they correspond to but you would likely be doing this anyway for organization and maintenance reasons.

I kept the same behavior as your workspace. The image is toggled if you keep clicking on the same button. If you want it to keep showing the image with repeated clicks on the same button then you can change 'toggle' in the code to 'show'

Also, I decided to hide the div's in the css rather than in the script.

Here's the jQuery with comments:

// Attach a click handler to the parent ul instead of having 11 click handlers attached to the buttons
// The buttons will receive the clicks and they'll bubble up to the ul which will run the handler
// This is called event delegation
// You may need to change the selector to 'nav ul' if you will have more ul's on the page
$('ul').on("click", "button", function(){

  // Get the index of the li whose button was clicked
  var indexClicked = $(this).parent().index();

  // 1. Get the div at that same index and toggle it
  // 2. Get the siblings of that div and filter it down to the ones with the "center" class. The filter is needed to remove the nav element from the selection.
  // 3. Hide those siblings.
  $('.center').eq(indexClicked).toggle().siblings('.center').hide();
});

Good coding, Jason. However, there is one thing that needs addressed. You shouldn't hide the pictures via CSS because if a user has JavaScript disabled, they won't be able to see any of the pictures. If you hide them via JavaScript, then at least if it is disabled, they will be able to see the pictures.

Thanks.

That's true and a valid point but Ana didn't give any details on what should happen if javascript is disabled. The intended behavior was to show 1 image. We don't know the context here and maybe it's not desirable to see all images at once and something else should happen entirely. I'm not saying what I did was "right" in the context of progressive enhancement but we don't have enough details to know what would be "right".

Another problem is that the nav is non-functional without javascript. Maybe that should be hidden in the css and shown with javascript. There's not much point in it being there if javascript isn't working.

If the goal is to display all the images if js is disabled then perhaps a more accessible approach would be to change the buttons to links (but style them to look like buttons) then each link could have a fragment identifier which would take you to the portion of the page where that div is located. The div's would need id's to match the fragment identifier.

That could even be the basis for a css only approach to this problem.

I forked the earlier codepen to show an example with 3 of the images: http://codepen.io/anon/pen/qEeKzQ?editors=110

It's going to have some differences whether good or bad. The url is going to change and I think you lose the ability to toggle the image off if you click the same link again. I can't think of a way to solve that problem but maybe this is a reasonable tradeoff for the relatively small percentage of people with js disabled.

Use the css version for them and the jQuery version takes over if js is enabled.

Ana Camelo
PLUS
Ana Camelo
Courses Plus Student 13,218 Points

Thanks a lot for all you help! It is working jus great now! :)