Bunkai.Satori
Bunkai.Satori

Reputation: 4758

OnMouseOver event and storing variable values

I am generating an HTML table dynamically using JavaScript. One of the table's columns contains an onmouseover event, and when the mouse cursor is over a particular cell, I wish to display cell specific information.

In my case, I wish to display the value of nPos via an alert() call as it was during the table construction.

Simplified example of my table creation:

for (var iLoop = 0 ; iLoop < nHitsPerPage ; iLoop++) {
    var nPos = (nCurrentPageParam * SearchResults.nMaximumHitsPage) + iLoop;

    //...

    var cellInfo = tableResultsRow.insertCell(6);

    //...

    cellInfo.className = "noWrapCell";
    cellInfo.innerHTML = "?";
    cellInfo.style.cursor = "pointer";

    // The line below is important - I need to store nPos value during the table consturction
    cellInfo.onmouseover = function(){alert("nPos = " + nPos)};
    cellInfo.onmousemove = function(){FileResort.LightboxShortInfo.update(event)};
    cellInfo.onmouseout = function(){FileResort.LightboxShortInfo.hide(event)};
}

As you can see from the example above, I iteratively created a table within my for() loop. I want to store the value of the nPos within every row (record) which is different for each row (record).

My problem is that once I mouseover that particular cell, I get the same nPos value for every row (record), and that nPos is the current value of nPos at the particular application state.

I cannot find a way to record the nPos value as it was during the for() execution, which is important for me in identifying what record is stored in the particular row.

Is there a way to capture, or store the value of nPos for every row (record) during the table's initial construction?

Upvotes: 1

Views: 2765

Answers (2)

kuroi neko
kuroi neko

Reputation: 8661

You are yet another victim of the closure monster :)

Look at this:

cellInfo.onmouseover = function(){alert("nPos = " + nPos)};

the function here - let's call it lambda - will have to find the value of the variable nPos. Since nPos is not declared inside lambda, it will look for it in the upper level function, that is the function where nPos is created.

When the mouseover event will fire, the code that declares and sets nPos will already have run to completion, so nPos will have the value nHitsPerPage.

That is exactly what lambda will display. Unfortunately, that's not what you want :).


To get over that, you need to create a (lexical) closure, i.e. provide lambda with a value of nPos that suits your needs.

The way of doing it in Javascript is as follows:

cellInfo.onmouseover = function(p){
    return function () { alert("nPos = " + p)};
    } (nPos);

let's call nu the new function (the one that takes p as a parameter). We changed lambda so that it now refers to p instead of nPos.

It means that when the mouseover event will fire, lambda will look for p in its upper function, which is now nu. And it will indeed find p there, as the parameter of nu.

p is a function parameter, so it recieves a copy of nPos at the time it is called. It means lambda will refer to a different instance of nu's calling context for each instance of cellInfo.

Each instance of the mouseover event handler will now hold a copy of p that is set to the desired value of nPos.

Upvotes: 2

Abraham Hamidi
Abraham Hamidi

Reputation: 13809

Quick Psuedo Code:

var nPosArray = [];
var itemsArray = [];

for (var iLoop = 0 ; iLoop < nHitsPerPage ; iLoop++)
{
    var nPos = (nCurrentPageParam * SearchResults.nMaximumHitsPage) + iLoop;

    //...

    var cellInfo = tableResultsRow.insertCell(6);

    //...

    cellInfo.className = "noWrapCell";
    cellInfo.innerHTML = "?";
    cellInfo.style.cursor = "pointer";

    // The line below is important - I need to store nPos value during the table consturction
    nPosArray.push(nPos);
    cellInfo.addEventListener('mouseout', cellMouseOut(event));

    cellInfo.onmousemove = function(){FileResort.LightboxShortInfo.update(event)};
    cellInfo.onmouseout = function(){FileResort.LightboxShortInfo.hide(event)};
    itemsArray.push(cellInfo);
}

function cellMouseOut(e)
{
    for(iLoop = 0 ; iLoop < cellInfo.length; iLoop++)
    {
        if(e.target.id == cellInfo[iLoop].id)
        {
            alert('NPos: ' + nPosArray[iLoop]);
        }
    }
}

Upvotes: 0

Related Questions