4

I have this code:

            $('.counter_d').mouseover(function() {
                   $('#description').html('Counter');
             });
            $('.selector_d').mouseover(function() {
                   $('#description').html('Selector');
             });
             $('.date_d').mouseover(function() {
                   $('#description').html('Date');
             });

and several more, but I think the file could be smaller and even reusable using loops, but I'm not able to bind the description (HTML method) with the selector.

I want to use something like this:

              var selectors=['.counter_d','.selector_d','.date_d'];
              var description=['Counter', 'Selector', 'Date'];


              for(var i=0; i<selectors.length; i++)
                 $(selectors[i]).mouseover(function() {
                   $('#description').html(description[i]);
                 });

Any help? Thanks

Chris Johnson
  • 20,650
  • 6
  • 81
  • 80
Frank
  • 53
  • 4
  • Please post your markup. – Ram Sep 09 '12 at 01:23
  • Try to use `description[i]` as a variable and not as a string literal. So remove the embracing `' '`. – nuala Sep 09 '12 at 01:25
  • ups , sorry, yeah, in this example I added the extra '' :P – Frank Sep 09 '12 at 01:28
  • Thank you guys! I needed this code, because several columns in a table had to have a description , which had to change depending in the position of the mouse, and the table could change depending of the needs – Frank Sep 09 '12 at 01:37

6 Answers6

8
var selectors = {
    '.counter_d': 'Counter',
    '.selector_d': 'Selector',
    '.date_d': 'Date'
};


$.each(selectors, function (key, value) {
    $(key).mouseover(function () {
        $("#description").html(value);
    });
});

Example: http://jsfiddle.net/andrewwhitaker/bS28q/

Andrew Whitaker
  • 124,656
  • 32
  • 289
  • 307
  • 3
    I wanted to post very similar answer, giving this code as an example: http://jsfiddle.net/vxd9n/, but you were quicker. You could however extract `$('#description')` outside the event handler, because it is not needed to be executed every time the event handler is fired. If you will put it in the callback for `$.each()`, it will be executed for every element of `selectors`. Thus, it would be better to put it where `selectors` are defined. Anyway, worth upvoting. +1 – Tadeck Sep 09 '12 at 01:34
1

The problem is the variable i is assigned to 3 at the time the mouseover callback is executing.
As description[3] is undefined no new HTML is assigned.
Fiddle enable your browser console to read the console.log!

I think a more elegant solution is to give the HTML elements an extra attribute description and in the mouseover callback simply do:

$('#description').html($(this).attr("description"));

(You see it in the fiddle above)

In my opinion you can even select all elements in a more elegant way and get rid off the loop as jQuery will handle this for you:

$(".counter_d, .selector_d, .date_d").mouseover(function() {
    $('#description').html($(this).attr("description"));
});

updated Fiddle

nuala
  • 2,681
  • 4
  • 30
  • 50
  • It depends on some other factors (eg. how many elements having these classes assigned are actually on the page - if tens or hundreds, then it is not a good idea to add description to each). However, this idea is worth mentioning. Also +1 for mentioning why it is not actually working - would you mind showing the solution for that (eg. using self-executing anonymous function)? – Tadeck Sep 09 '12 at 01:42
  • I was supposed to update my answer but Andrew was faster with the same idea and got accepted. :) – nuala Sep 09 '12 at 01:47
  • I meant using anonymous function to overcome the limitation of simple `for` loop. You said "_`i` is assigned to 3_" and I hoped you could just solve the problem by making sure each event handler will receive proper value of `i`. It is feasible and even given as an example in various sources. I was referring to something like this: http://stackoverflow.com/a/750506/548696 (however creating separate variable storing function is not necessary, anonymous function will do also). – Tadeck Sep 09 '12 at 03:04
  • I have taken a shot and explained it a little in my answer, including examples. – Tadeck Sep 09 '12 at 07:14
1

Since correct solutions have already been given (Andrew Whitaker's accepted answer being my favorite), I will actually tell you what is the problem with your code (yoshi's answer has some clues, but does not explain it in detail).

The problem

The problem is, that even though the value of i changes within the loop, when it is executed, i stays the same (the same as when the for loop has ended) when event handlers are executed.

What really happens within your code

The proof looks like this (see jsfiddle):

var selectors=['.counter_d','.selector_d','.date_d'];
var description=['Counter', 'Selector', 'Date'];

for(var i=0; i<selectors.length; i++)
    $(selectors[i]).mouseover(function() {
        $('#description').html(i); // i is always equal to 3
    });​

The problem is event handlers use i from outer scope, which at the time of handlers' execution is equal to 3. So even though the i variable has the value you wanted when handlers are attached, the value changes before they are executed.

The solution

To solve that, you can slightly modify your code to use anonymous functions that are immediately called by passing it then-correct value of i:

var selectors=['.counter_d','.selector_d','.date_d'];
var description=['Counter', 'Selector', 'Date'];
for(var i=0; i<selectors.length; i++)
    (function(i){
        $(selectors[i]).mouseover(function() {
            // i is the same as when the outer function was called
            $('#description').html(description[i]);
        });
    })(i); // executing function by passing current i
​

To prove that it works correctly: http://jsfiddle.net/ZQ6PB/

See more

JavaScript closure inside loops - simple practical example,

Community
  • 1
  • 1
Tadeck
  • 132,510
  • 28
  • 152
  • 198
0

I'd go for something like this:

var obj = {
    'a': 'content a',
    'b': 'content b',
    'c': 'content c'
};

$('.a,.b,.c').mouseover(function() {
    $('#d').html(obj[this.className]);
});​

DEMO

Don't really like loop idea, since it makes it much less readable.

UPD: You can always expand the solution for more classes

var obj = {
    '.a': 'content a',
    '.b': 'content b',
    '.c': 'content c'
};

var selector = Object.keys(obj).join(',');
$(selector).mouseover(function() {
    $('#d').html(obj['.' + this.className]);
});​

DEMO

Maksim Vi.
  • 9,107
  • 12
  • 59
  • 85
  • Maybe your solution is more readable (I don't agree with that), but Andrew's solution works in case you have more classes assigned to the elements you attach events to. In other words: I don't think your solution is correct, because it can be easily broken by doing something that shouldn't break it (namely: adding some other classes, unrelated to your script). – Tadeck Sep 09 '12 at 01:37
  • As a proof that you can easily break it without being aware you are doing something the script will not handle: http://jsfiddle.net/H7rNy/2/ – Tadeck Sep 09 '12 at 01:40
  • Sure, you can also break it by division by zero somewhere on the page. It's trivial to fix it, but i don't see this problem in the original question. – Maksim Vi. Sep 09 '12 at 01:49
  • No, I am actually referring to the problem introduced by _your_ script, not by someone else's. In case of your script, if you add any class (which is very common approach, a lot of plugins add some classes eg. for marking some stuff temporarily; using classes is extremely popular way for managing the way elements are presented also) to one of the elements you attach events to, the whole thing won't work. So, in this case, using the solution from your answer, not adding some classes, is actually comparable to dividing by zero. – Tadeck Sep 09 '12 at 03:00
  • in the given case my script doesn't introduce any problems, thanks for -1 by the way. I don't really know why you're so concerned. I'd take it from the OP, as it would be constructive. – Maksim Vi. Sep 09 '12 at 03:59
  • I gave you -1, because you have shown no effort to actually get rid of the problem I reported. OP probably will use it for something like menu (where every item may have `menu-item` class) or eg. thumbnails (where every item may have `thumbnail` item). It is natural to add classes to elements as soon as you need them. In all the above cases your solution will fail and you know it. It works when you have only one class assigned to element. OP made a good choice by not selecting your answer, it means something. For sure, the correct answer will work properly in mentioned cases. – Tadeck Sep 09 '12 at 06:55
  • I am saying this for a last time: your solution does provide "kind of" answer, but introduces several other problems. I know, because part of my work was (still iss) fixing such stuff or teaching people not to do it (although most people understand why). So it is part of my life (the professional one).Why am I? SO user, we deserve correct answers, not offensive comments. – Tadeck Sep 09 '12 at 09:57
  • 2
    Downvoting and commenting harmful answers is not trolling. Also please read [faq] carefully, especially sections: [Etiquette](http://stackoverflow.com/faq#etiquette) (what you are not doing), [What if I see bad things happening?](http://stackoverflow.com/faq#flagging) (what I did). – Tadeck Sep 10 '12 at 17:55
0

It looks like your selectors all end with _d. It seems reasonable that we could do the following.

$('[class$=_d]').mouseover(function(){
    var str = $(this).prop('class').split('_')[0];
    var desc = str.charAt(0).toUpperCase() + str.slice(1);
    $('#description').html(desc);
});
Ohgodwhy
  • 49,779
  • 11
  • 80
  • 110
0

Constructing the HTML as follows (assuming the elements are spans) ...

<span class="d counter_d" data-desc="Counter">...</span>
<span class="d selector_d" data-desc="Selector">...</span>
<span class="d date_d" data-desc="Date">...</span>

... allows the javascript to as simple as this :

var $description = $("#description");

$(".d").mouseover(function() {
    $description.text($(this).data('desc'));
});

The class names '.counter_d','.selector_d','.date_d' are redundant and can be deleted unless they are required for some other reason - eg. styling.

Of course, if you had hundreds of such elements, then the HTML would be a pain to write handraulically. You would be better off with another approach.

Beetroot-Beetroot
  • 18,022
  • 3
  • 37
  • 44