views:

78

answers:

4

Hi all, I'm wondering if its possible to make the following code more concise:

 $('#americasTrigger').hover(
  function () {
          $('#americasImg').fadeIn()
      },
  function(){
          $('#americasImg').fadeOut()
  }
  );

$('#europeTrigger').hover(
  function () {
      $('#europeImg').fadeIn();
  },
  function(){
      $('#europeImg').fadeOut();
  }
  );    

$('#middleEastTrigger').hover(
  function () {
      $('#middleEastImg').fadeIn();
  },
  function(){
      $('#middleEastImg').fadeOut();
  }
  );    

//More etc

The country name stays the same for each, with 'Trigger' or 'Img' added to the end. There alot of repetition here which indicates to me im not going about the this best way.

I had thoughts around:

  • Crearting a case scenario, or
  • Somehow getting the selector being used for a selection, making it a string, splitting it's name to capture the country in use and applying that to the nested fadeIn/Out function with 'Img' on the end.

Is this possible or am I being to fancy?

Edit 1: Thanks verymuch for all the responses, apologies for not posting the html, i've put this bellow. In short I'm using image maps over a bg image (of earth) as the hover triggers for fading in/out my absolutely positioned on-hover images.

<div class="mapTub"> 

  <img src="images/transparentPixel.png" class="mapCover" usemap="#worldMap" width="524px" height="273px"/>

  <map name="worldMap" id="worldMap">
    <area id="americasTrigger" shape="poly" coords="1,2,3" href="#americas" />
    <area id="europeTrigger" shape="poly" coords="4,5,6" href="#europe" />
    <area id="middleEastTrigger" shape="poly" coords="7,8,9" href="#middleEast" />
  </map>

<img src="images/International_americas_dark.png" class="americas" id="americasImg" />
<img src="images/International_europe_dark.png" class="europe" id="europeImg" />
<img src="images/International_middleEast_dark.png" class="middleEast" id="middleEastImg"  />

</div>

Reigel's answer seems like the way to go here, ill try it out report back, further comments welcome! :)

+2  A: 

Me, without knowledge of the html, suggest this...

$('#americasTrigger, #europeTrigger, #middleEastTrigger').hover(
    function () {
        var id = this.id;
        $('#'+id.replace('Trigger', 'Img')).fadeIn();
        //$('#'+id.slice('0',id.indexOf('Trigger'))+'Img').fadeIn();
    },
    function(){
        var id = this.id;
        $('#'+id.replace('Trigger', 'Img')).fadeOut();
        //$('#'+id.slice('0',id.indexOf('Trigger'))+'Img').fadeOut();
    }
);

You can also use .replace() as suggested by Anurag in the comment below...


id ='europeTrigger';
alert(id.slice('0',id.indexOf('Trigger'))); // alerts 'europe'
// '#'+id.slice('0',id.indexOf('Trigger'))+'Img' is '#europeImg'

demo

Reigel
you could replace that with `id.replace('Trigger', 'Img')`
Anurag
@Anurag haha nice! wait, updating...
Reigel
Nice one Reigel, this worked a treat, thanks!
demolish
+2  A: 

Since it looks like you are accessing only unique ids, your best choice is to use a lookup table IMO.

var lookmeup = [  [$('#americasTrigger'), $('#americasImg')],
                  [$('#europeTrigger'), $('#europeImg')],
                  [$('#middleEastTrigger'), $('#middleEastImg')]
               ];

$.each(lookmeup, function(index, element){
    element[0].hover(function(){
      element[1].fadeIn();
    }, function(){ 
      element[1].fadeOut();
    });
});

DRY! all done!

Another way to do it in a more efficient manner would be to use event delegation.

If all of your hover elements have the same TAG, this approach could be useful:

$(document.body).delegate('div', 'mouseenter', function(e){
     $('#' + e.target.id.replace(/Trigger/, 'Img')).fadeIn();
});

$(document.body).delegate('div', 'mouseleave', function(e){
     $('#' + e.target.id.replace(/Trigger/, 'Img')).fadeOut();
});

Assuming that all your "hoverable" elements were DIVs. You still should give those elements a classname so that only those specific elements are targeted.

It makes a lot of sense to confine the root element for delegate(). Here I use document.body which would .live() do. The great thing about .delegate() is, that if your hover elements share one parent node, you can apply delegate() on that node. In that manner you reduce the number of event handlers bound

(2 instead of 6).

jAndy
Hey jAndy, this looks good too, I've just posted the html code in the original op, do you have any thoughts around your deligate method vs Reigal's slice/replace method above in terms of performance?
demolish
A: 

lol, looks like this may be about the same size or longer than your code, but definitely dryer.

Thanks to @Andy for pointing out the performance penalty with the previous version using $(..).each.

var regions = ['americas', 'europe', 'middleEast'];

$.each(regions, function(region) {
    var trigger = id(region, 'Trigger');
    var image = id(region, 'Image');

    $(trigger).hover(
        effect(image, 'fadeIn'),
        effect(image, 'fadeOut'),
    );
});

function effect(selector, method) {
    return function() {
        $(selector)[method]();
    };
}

function id(prefix, suffix) {
    return '#' + prefix + suffix;
}

If you can change the HTML, I would encode all knowledge into the page itself, and just use jQuery to setup hover events.

<div class='trigger' data-image='#americasImg'>
   ..
</div>
<div class='trigger' data-image='#europeImg'>
  ..
</div>

Javascript

function imageId(elem) {
    return $(elem).attr('data-image');
}

// Using the fade function from before
$('.trigger').hover(
    effect(imageId(this), 'fadeIn'),
    effect(imageId(this), 'fadeOut')
);
Anurag
I would use `$.each()`, no extra jQuery constructor needed. Is the underscore as the first parameter a very special trick or typo? :)
jAndy
@jAndy - thanks for the tip. I never realized the performance penalty. (just didn't like the look of `$.each` but I guess its a necessary evil :). The underscore was just a signal to indicate that the parameter is useless.
Anurag
A: 

Or, to make things much simpler, add a marker class, called 'fadingImage' for example, to each of the images and then use this code...

$('.fadingImage').hover( 
    function () { 
        $(this).fadeIn() 
    }, 
    function(){ 
        $(this).fadeOut() 
    } 
); 

This works because all of the images, regardless of their id, are handled in the same way, al that you really need to do is identify which images on your page need to have the hover handlers attached, and this is done with the marker class. You might even be able to dispense with the ids altogether, if they aren't used for anything else.

Update: No that I've woken up (Thanks jAndy & Reigel!), I'll amend my post to deal with the fact that the element being hovered is not the one that is being faded.

Without having any sample markup, I'm going to have to make some assumptions, but the original poster may want to provide the real markup, in order to put things in context.

<div>
    <span class="fadingTrigger">first text to hover over<span>
    <img class="fadingImage" src="..." alt="first image to be faded"/>
<div>
<div>
    <span class="fadingTrigger">second text to hover over<span>
    <img class="fadingImage" src="..." alt="second image to be faded"/>
<div>

$('.fadingTrigger').hover( 
    function () { 
        $(this).parent().find(".fadingImage").fadeIn() 
    }, 
    function(){ 
        $(this).parent().find(".fadingImage").fadeOut() 
    } 
); 

Depending on the markup structure, the method of finding the fadingImage that is associated with the fadingTrigger may have to vary, but by having some well defined structure, it should be reliable.

The reason why I'd prefer this method over using an array of ids to lookup the elements is that any additions to the markup would require changes to the javascript - this would be especially problematic if the markup is dynamically generated. The javascript could be dynamically generated too, to include the appropriate array of values, but the would violate the DRY principal.

belugabob
+1 more simplified =)
Ninja Dude
this does not work since the OP uses different elements / ids for hovering.
jAndy
Yes, but there is no need for him to do so - he even admits, himself, that his code is very repetitive.
belugabob
@belugabob: where?
jAndy
@belugabob sure! that might work... but what if the image is not the one to be hovered?... e.g. something has to trigger image fades.. ;)
Reigel
@jAndy - the first paragrah after his code sample
belugabob
@Reigel, if the image is not the one to be hovered, then don't mark it with the 'fadingImage' class
belugabob
LOL I hope this guy is just joking.. ;)
Reigel
@belugabob the image needs to fade (your doing it right now)... But the image needs to fade if something is hovered... and not the image being hovered.. ;)
Reigel
belugabob
And all the sudden the simplified post explodes :-) j/k
jAndy
The javascript is no more complicated than the examples that dynamically generate the image id from the trigger id.
belugabob