Show / Hide div on top of one of toggled images?

Hi,

I’m just learning jquery because I’m building a site for a friend (in wordpress) and want to use some animation instead of loads of pages.

What I want to achieve is essentially to show the outside of a building and when a user clicks on it it changes to a view of the inside. I’ve managed to get that far using code like this http://jsfiddle.net/M9QBb/91/ (once I figured out I needed to use the ready function as well - total newbie! :rolleyes:)

The next step is though that once the inside of the building is shown, a div should also show with a closed scroll and when a user clicks on the closed scroll, this div should be either expand or be swopped for one where you can see the writing.

I was going to create a div with a background image of a closed scroll and one with the background image as an open scroll that I can then write text in - this way once I show my friend how to use wordpress it should be easy enough for her to change the text as needed (plus the effect will be repeated on several pages).

I was just wondering whether this was possible and also whether its the best way of doing it?

Many thanks for any help,

Thanks

Andrew

Hi there,

This sounds like a reasonable approach.
Is there any aspect of this that you are having trouble with?

Hi Pullo,

Thanks for replying.

At the moment the only jquery code I have is this:

jQuery(function(){
jQuery(“#infoToggler”).click(function() {
jQuery(this).find(‘img’).toggle();
});
});

and the html is simply

<div id=“infoToggler”>
<img alt=“” src=“http://devplay.co.uk/wp-content/uploads/2013/06/first.jpg” width=“960px” height=“667px” />
<img style=“display: none;” alt=“” src=“http://devplay.co.uk/wp-content/uploads/2013/06/second.jpg” width=“960px” height=“667px” />
</div>

I’m just not sure how I’d make the div with the closed scroll as a background appear when the second.jpg is showing but disappear again when the infoToggler div toggles back to showing first.jpg?

Once I’ve got that to work then I assume that I can setup another function along the lines of

jQuery(function(){
jQuery(“#scrollDiv”).click(function() {
// code to toggle between 2 divs scrollClosed and scrollOpen
});
});

Thanks

Andrew

Hi there,

You could do it like this:

<!DOCTYPE HTML>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Toggle images</title>
    <style>
      .hidden{display:none;}
    </style>
  </head>
  
  <body>
    <div id="infoToggler">
      <img alt="" src="http://devplay.co.uk/wp-content/uploads/2013/06/first.jpg" width="960px" height="667px" class="one"/>
      <img alt="" src="http://devplay.co.uk/wp-content/uploads/2013/06/second.jpg" width="960px" height="667px" class="two hidden"/>
    </div>

    <script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
    <script>
      $("#infoToggler").click(function() {
        $(this).find('img').toggle();
        if ($(".one").is(":visible")){
          console.log("Make scroll appear here");
        } else {
          console.log("Make scroll vanish here");
        }
      });
    </script>
  </body>
</html>

Thanks Pullo,

That’s very helpful I will do some work on that tonight and try and get something working :slight_smile:

I thought I might have to do something using an ‘If’ block but wasn’t sure how to reference what was showing.

So from the above code I can test its working using the console and once it is I can make the div with the closed scroll appear and hide depending on which image is showing (and use CSS to position and set the Z order).

Am I correct in thinking that I would have a second toggle function on the scrollDiv to swop between the closedScrollDiv and the openScrollDiv?

Thanks,

Andrew

Hi,

Yup, that’s correct. It’s always a good idea to break a problem down into lots of small steps and implement them one by one.

That sounds like it should work.
Let me know if you need any more help with this :slight_smile:

Thanks Pullo,

Will work on it tonight now I know what approach to take and where to start :slight_smile:

Will let you know how I go and thanks for the help so far,

Andrew

Hi Pullo,

I’ve had a play with this tonight and I think I’ve got it working (just need to use real images and set scrollDiv background images) :slight_smile:

The page I’ve been working on it with is here - http://devplay.co.uk/toggle-play/

I’ve put a copy of the code below but have a couple of questions…

jQuery(function(){
	jQuery("#infoToggler").click(function() {
	jQuery(this).find('img').toggle();
	if (jQuery(".two").is(":visible")){
          console.log("Make scroll appear here");
		jQuery(".closedScroll").show();
        } else {
          console.log("Make scroll vanish here");
		jQuery(".closedScroll").hide();
		jQuery(".openScroll").hide();
        }
});
});

jQuery(function(){
	jQuery("#scrollToggler").click(function() {
	jQuery(".closedScroll, .openScroll").toggle();
});	
});

First (newbie! lol) question is do I need separate functions like this or rather, is there any reason not to do it this way? Second question is that I’m wondering whether it is possible to do an image map type thing for infoToggler part so that it only fires when a user clicks on a certain part of the image (which would be a door in this case)?

<div id="infoBoxes">
<div id="infoToggler"><img class="one" alt="" src="http://devplay.co.uk/wp-content/uploads/2013/06/first.jpg" width="960px" height="667px" /><img class="two hidden" alt="" src="http://devplay.co.uk/wp-content/uploads/2013/06/second.jpg" width="960px" height="667px" /></div>
<div id="scrollToggler">
<div class="closedScroll hidden">Closed scroll image only</div>
<div class="openScroll hidden">Open scroll where we can write lots of text and information etc.</div>
</div>
</div>
.hidden {display:none;}

.closedScroll {width: 100px; height: 300px; border: 1px solid black; position: absolute; top: 300px; left: 20px; cursor:pointer;}
.openScroll {width: 550px; height: 300px; border: 1px solid red; position: absolute; top: 300px; left: 20px; cursor:pointer;}

#infoBoxes {
width: 960px;
height: 667px;
position: relative;
}

Next question (and possibly not relevant to this sub forum) - I’m afraid some of this css is stuff I haven’t used much either - mainly the positioning stuff. It seems to work fine as I’ve set it up here but should I set a Z-index value on the scrollToggler div just to be sure it always appears on top? I’ve also not set any position value for the infoToggler div but thought it should be fine as its the same size as the infoBoxes div - seems to work but not sure its the ‘correct’ way of doing it?

As an extra bonus, I’m using Wordpress for this site and using your suggested .hidden{display:none;} instead of an inline display: none; means that all the elements show up in the editor which I thought I was going to have problems with and end up having to enter all the text in code/text view :slight_smile:

Thanks for all your help with this, really good to be able to get it working fairly pain free in a much shorter time than I expected,

Andrew

EDIT to above: I just noticed that in internet explorer I can only click on the openScroll and closedScroll divs to toggle between them if I am over the text - is there a way to make the whole div clickable as I only intended to have the background image on the closedScroll div without any text at all…

Yes, there is. You just add a background image to them.

Hi there,

jQuery(function(){...}

is a shortcut for

jQuery(document).ready(function(){...});

If you place all of your code before the closing </body> tag, you can forget about this altogether.
Otherwise you only need to do it once, not twice as you have.

Sure. Here’s an example:

<map name="Map" id="Map">
  <area shape="rect" coords="32,36,222,109" href="#" />
  <area shape="rect" coords="246,45,420,110" href="#" />
</map>

$('map area').click(function(){
   alert("You clicked the image map");
});

If you need to drill this down further, you can filter certain areas of the map based on their (for example) href attribute.

AFAIK that isn’t necessary.

No, that’s fine. It is positioned relative to its parent.

That’s good to hear :slight_smile:
It’s a good practice to try and avoid excessive inline CSS when writing JavaScript, as this will make your markup rather convoluted.

Hi Pullo,

Thanks for getting back to me again and clearing those things up :slight_smile:

I started off by using the code as shown in here - http://jsfiddle.net/M9QBb/91/ - but at first I couldn’t get it to work in my Wordpress install but eventually I noticed that if I changed the settings in JSFiddle from onload (which worked) to no wrap in <head> it stopped working which was the problem I was having - at first I thought I had linked the .js file wrong or something but it seems it was because I’d added the link to my header file.

To get around that, after some googling, I added in the

jQuery(document).ready(function(){...});

block and checked it then worked, which it did so I then changed it to

jQuery(function(){...}

Now its working I’ll probably look into adding it into the functions.php file instead which might (or might not) change the need for the .ready() block. Learning more about how jquery is loaded and at what time etc is something else I need to know more about especially with the number of files loaded for a theme in Wordpress.

In the meantime though I guess I can change my code to:


jQuery(function(){
	jQuery("#infoToggler").click(function() {
	jQuery(this).find('img').toggle();
	if (jQuery(".two").is(":visible")){
          console.log("Make scroll appear here");
		jQuery(".closedScroll").show();
        } else {
          console.log("Make scroll vanish here");
		jQuery(".closedScroll").hide();
		jQuery(".openScroll").hide();
        }
});
        jQuery("#scrollToggler").click(function() {
	jQuery(".closedScroll, .openScroll").toggle();
});	
});

Once again thanks for your help with this, it’s very much appreciated and has saved me an awful lot of time and frustration! :slight_smile:

Regards

Andrew

Hi Andrew,

I’m not sure in what order JSFiddle does what and it’s not a big deal to wrap everything in a $(document).ready() callback. I would just leave that as it is.

One thing that you might be interested in however, is that when using the jQuery library included with WordPress, you can pass in the dollar as a parameter to the aforementioned callback and write this:

jQuery(document).ready(function($){
  $("#infoToggler").click(function(){  ... });
  ...
});

instead of this

jQuery(document).ready(function($){
  jQuery("#infoToggler").click(function(){  ... });
  ...
});

The reason behind this is a syntax issue, the jQuery library included with WordPress loads in “no conflict” mode. This is to prevent compatibility problems with other JavaScript libraries that WordPress can load.

For full details see WordPress Codex

That’s fine as it is and it does the job, but I would still make the following changes:

Here’s what we end up with:

<!DOCTYPE HTML>
<html>
  <head>
    <meta charset="utf-8">
    <title>Toggle images</title>
    <style>
      .hidden{display:none;}
      .closedScroll{width: 100px; height: 300px; border: 1px solid black; position: absolute; top: 300px; left: 20px; cursor:pointer;}
      .openScroll{width: 550px; height: 300px; border: 1px solid red; position: absolute; top: 300px; left: 20px; cursor:pointer;}
      #infoBoxes{width: 960px; height: 667px; position: relative;}
    </style>
  </head>
  
  <body>
    <div id="infoBoxes">
      <div id="infoToggler">
        <img class="one" alt="" src="http://devplay.co.uk/wp-content/uploads/2013/06/first.jpg" width="960px" height="667px" />
        <img class="two hidden" alt="" src="http://devplay.co.uk/wp-content/uploads/2013/06/second.jpg" width="960px" height="667px" />
      </div>
      <div id="scrollToggler">
        <div class="closedScroll hidden">Closed scroll image only</div>
        <div class="openScroll hidden">Open scroll where we can write lots of text and information etc.</div>
      </div>
    </div>
    
    <script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
    <script>
      jQuery(function($){
        var $images = $("#infoToggler").find('img'),
            $scrolls = $(".openScroll, .closedScroll"),
            $openScroll = $(".openScroll"),
            $closedScroll = $(".closedScroll");
        
        $("#infoToggler").on("click", function(){
          $images.toggle();
          if ($images.first().is(":visible")){
            $scrolls.hide();
          } else{
            $closedScroll.show();
          }
        });
        
        $("#scrollToggler").on("click", function(){
          $scrolls.toggle();
        });  
      });
    </script>
  </body>
</html>

Hope that helps.

Thanks Pullo that’s great :slight_smile:

It’s certainly good to know that the $ can be passed in and will save quite a bit of typing!

I’ve read through the links you’ve added and understand the point of removing the console.log and using variables.

I’m not quite as clear on the use of on() as it seems quite a subtle change for my current level of knowledge/understanding but it looks like it should make the code more flexible and robust for future, more complicated functions. On reading the link I’m also not sure whether it might mean I wouldn’t have needed the .ready() callback if I’d have used this method but I might be misunderstanding the dynamic part…

Anyway, in the meantime I’ll certainly implement it as you suggest and maybe read up a bit more on it or wait until my understanding is better and come back to again :slight_smile:

Thanks again for your help, now I’ve got this working I’m looking forward to playing around with more jQuery code that I can put into practise on future projects.

Regards

Andrew

Hi,

No problem whatsoever :slight_smile:

Just quickly about the use of the .on() method:

  • You are right, it makes the code more future-proof and is AFAIK, the preferred way to do things.
  • It also helps with event delegation which is what you should do when you have many elements which need the same event handler. For example consider this:

    <ul class="foo"> <li class="bar"></li> <li class="bar"></li> <li class="bar"></li> <li class="bar"></li> <li class="bar"></li> ... loads more li.bar elements ... </ul>

    Imagine we want to attach an event handler to each .bar element. The problem is that event listening is resource consuming, so instead of writing:

    $('.bar').on('click', function(){ console.log('Clicked bar!'); });

    a better approach would be to add a super event handler on a node which is a parent to every node that wants to listen to that event:

    $('.foo').on('click', '.bar', function(){ console.log('clicked bar!'); });
  • This has the added advantage that event handling done directly on a node works for just that node, forever. In other words, if we were to dynamically add more list elements with the class “bar” to <ul.foo>, they would also respond to clicks.
  • You can also use the .off() method to remove behaviour. Very nice!

Hi Pullo,

Thanks for the explanation / example, certainly seems to make more sense to apply it to the parent div instead of each one.

I can see why its a major advantage, both in terms of resources and it picking up any new elements that are added in dynamically, and as you say, looks like a better technique / better coding practise.

Will amend my code and try to ensure that I use this approach in future coding (just need to check my jQuery version in Wordpress to make sure it 1.7 or above or update if needed :slight_smile: )

Thanks

Andrew