tags:

views:

1784

answers:

4

The HTML looks kind of like:

<dl>
  <dt>
    <img src='Images\Something\expand-close.gif' /> Something 1
  </dt>
  <dd>Something 1 Text</dd>
</dl>

This HTML is repeated 1 or more times so there could be many instances of the HTML on the same page.

The Jquery I am using to expand the dd and replace the image is:

$("dl").find("dt").click(function() {
  // toggle the dd
  $(this).next().toggle(200);

  // replace the expand / close image
  var img = $(this).find("img");
  var src = img.attr("src");
  if (src.lastIndexOf("open.gif") != -1)
  {
    img.attr("src", src.replace("open.gif", "closed.gif"));
  }
  else
  {
    img.attr("src", src.replace("closed.gif", "open.gif"));
  }
});

This all works fine and does exactly what I need it to do. My question is, can the JQuery function be done better? I am relatively new to using JQuery and this one was a snippet I rattled off. If it could be done better, please explain the changes as I am trying to learn how to write better JQuery code. Any other pointers or suggestions would be appreciated as well.

A: 
<dl>
  <dt class="something">
    <img class="switch" src='Images\Something\expand-close.gif' /> Something 1
  </dt>
  <dd>Something 1 Text</dd>
</dl>

$('.something').click(function() {
    // toggle the dd
    $(this).next().toggle(200);
    // replace the expand / close image
    var img = $(this).find('.switch');
    var src = img.attr('src');
    if(src.lastIndexOf('open.gif') != -1)
        img.attr('src', src.replace('open.gif', 'closed.gif'));
    else
        img.attr('src', src.replace('closed.gif', 'open.gif'));
});
chaos
why did you add the id if you never used it?
TStamper
and wouldn't this be less efficient because instead of tag name selector, it would have to look for class "something" meaning checking every element?
TStamper
Habit, really. It felt like the sort of situation where an ID was going to be called for eventually. Not necessary to the question, though, so I took it out.
chaos
And yeah, it is less CPU efficient. I'm just working to my own idea of "better". :) I don't like working in terms of raw tag hierarchy because it feels error-prone and maintenance-fragile to me.
chaos
good reasoning..just making sure
TStamper
+2  A: 

You can set an ID or Class attribute to the image tag, which will clear up your code a bit. I'd also recommend using a plugin - there are plenty of plugins for this sort of thing available online for free, and all it requires is one method.

HTML:

<dl>
  <dt>
    <img src='Images\Something\expand-close.gif' id='myimage' /> Something 1
</dt>
  <dd>Something 1 Text</dd>
</dl>

JavaScript (using jQuery):

$('#myimage').click(function(){
  $(this).parent().get(0).toggle(200);
  var src = $(this).attr('src');

  if (src.lastIndexOf("open.gif") != -1) {
    $(this).attr('src', src.replace("open.gif", "closed.gif");
  } else {
    $(this).attr('src', src.replace("closed.gif", "open.gif");
  }
});

Hope that helps a bit :)

Jamie Rumbelow
isn't a class or id selector slower than just calling the tag name?
TStamper
id selectors are BY FAR the fastest selectors
Paolo Bergantino
yea, you're right...its just the class one that is slower. I don't know what I was thinking
TStamper
This section is repeated X amount of times, so wouldn't I need to have unique IDs for each image? I will amend the above question to reflect that...
Kelsey
+3  A: 

It's pretty close. Try:

$("dl > dt").click(function() {
  var dd = $(this).next();
  if (dd.is(":visible")) {
    var newimage = "closed.gif";
    dd.hide(200);
  } else {
    var newimage = "open.gif";
    dd.show(200);
  }
  var img = $(this).find("img");
  img.attr("src", img.attr("src").replace(/(open|closed)\.gif$/, newimage);
});

The differences are:

  1. Just use "dl > dt" (or "dl dt" as appropriate) instead of the find syntax in that situation;
  2. This code looks at if the thing is visible or not rather than the src image, which could potentially get out of sync especially given the delay;
  3. The regex on the last line just replaces whatever is there with whatever is correct to cater for irregularities.
cletus
I like the idea to use "dl > dt". I knew about the syntax but totally forgot about it when implementing. I will definately use that. The rest is pretty slick as well.
Kelsey
There is just one tiny error in your code:img.attr("src", img.attr("src").replace(/(open|closed)\.gif$/, newimage));Needs the another ')' at the end. Other than that it works well!
Kelsey
+1  A: 

You can play around with the settings but here is the general idea, a combination of CSS and JS ...

<style>

 dl dt { background: transparent url(open.gif) no-repeat scroll top left; padding-left: 20px; }
 .open dt { background-image: url(close.gif); }

</style>

<dl class="open">
 <dt>Something 1</dt>
 <dd>Something 1 Text</dd>
</dl>

<script>

 $('dl dt').click(function()
 {
  $(this).next().toggle(200);
  $(this).parent().toggleClass("open",$('dd:visible',$(this).parent()).length);
 });

</script>
farinspace
Bonus points if you use a sprite for open/close images and just toggle the background position.
Chetan Sastry
additionally using CSS and JS combo will keep the design separate from the implementation
farinspace