2

I've encountered a weird problem with Javascript. What I was given is a string of certain format that I will try to create a table out of.

The table will only have a cell per row and the format of the string is:
Content needs to be displayed for each cell (row)
@
parameter that will be passed to the onmouseover event handler which gets called when the user moves their mouse over the displayed text.

The JS code:

// the string of format
var stringProof = document.getElementById("stringProof").value;
var arrayOfProof = stringProof.split("#");

// find the table
var table = document.getElementById("proofTable");
// remove what's within
table.innerHTML = "";

for(var i = currentIndex*4;i < end;i++)
{
    // iterative create the text, span, cell and row
    var currentStepProof = arrayOfProof[i];
    var elementsInCurrentStepProof = currentStepProof.split("@");

    var tr = document.createElement("tr");
    var td = document.createElement("td");

    var span = document.createElement("span");
    span.onmouseover = function() {alert(elementsInCurrentStepProof[1]);};
    var text = document.createTextNode(elementsInCurrentStepProof[0]);
    span.appendChild(text);
    td.appendChild(span);
    tr.appendChild(td);
    table.appendChild(tr);
}

The problem is it does not matter which rows the onmouseover function is triggered, it will only alert the parameter of the last row which means the parameter of last row's onmouseover function overwrites what was passed to the previous row's onmouseover functions.

Any thoughts? Thanks a lot!!~~

j883376
  • 1,125
  • 9
  • 18
user1935724
  • 554
  • 1
  • 6
  • 18
  • http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example – georg May 30 '13 at 00:00

2 Answers2

1

All your handler functions share exactly the same "elementsInCurrentStepProof" variable. Because it changes with every iteration of that for loop, all the handlers will "see" it in its final state (that of the last iteration).

You can give each handler its own copy of the value like this:

span.onmouseover = function(element) {
  return function() { alert(element); }
}(elementsInCurrentStepProof[1]);

By using an intermediary function, you create a new storage scope (a closure) for a copy of the value. Note that it's not enough to make a copy of "elementsInCurrentStepProof", because the value of that variable is a reference to an array. You need to pass the value of element 1.

BrunoLM
  • 97,872
  • 84
  • 296
  • 452
Pointy
  • 405,095
  • 59
  • 585
  • 614
  • I tried you code and now I am getting [object MouseEvent] as the onmouseover function gets called (everyone of them) – user1935724 May 29 '13 at 23:59
  • @user1935724 uhh ... are you *sure* you copied that code exactly as in my answer? The function that gets returned should not have a parameter. – Pointy May 30 '13 at 00:13
0

This will do the trick:

http://jsfiddle.net/BhLfk/

var span = document.createElement("span");
span.data = elementsInCurrentStepProof[1];
span.onmouseover = function(event) {alert(event.target.data);};

Please note your question is missing some information which make it a little bit harder to understand what you are trying to do.

bigbearzhu
  • 2,381
  • 6
  • 29
  • 44
  • @user1935724 To answer your question for getting [object MouseEvent], I think you may missed the part "(elementsInCurrentStepProof[1])" at the end of the line in the answer from Pointy, which forces the function to use specific parameter instead of the default mouse event. See my answer for a easier-to-understand solution. It is basically doing the same thing as Pointy's answer. – bigbearzhu May 30 '13 at 00:14