views:

31

answers:

2

The script I have been working on for a star rating system, saves the filled in stars with an onClick event and changes the onmouseover & onmouseout values to null so moving the mouse off them afterwards won't mess that up, and the form has multiple ratings and a clear button at the bottom, which i need to have reset the onmouseover & onmouseout events, through the function below, but within those, ratings[y] and x are taken to be literal rather than what they contain, and makes the onmouse events fail because the parameters are incorrect. How do I put in the variables when changing the events this way?

     var ratings = new Array("happy", "clean");
  for(y = 0; y < 2; y++)
  {
   for(x = 0; x < 5; x++)
   {
    fullname =  ratings[y] + '_' + x;
    document.getElementById(fullname).onmouseover = function onmouseover() { star_rate(ratings[y], x, 1); };
    document.getElementById(fullname).onmouseout = function onmouseover() { star_rate(ratings[y], x, 2); };
   }
  }
+1  A: 

You can do it by using a function call to create a next context for each handler (but see below), like this:

var ratings = new Array("happy", "clean");
for(y = 0; y < 2; y++)
{
    for(x = 0; x < 5; x++)
    {
        fullname =  ratings[y] + '_' + x;
        (function(thisx, thisy) {
            document.getElementById(fullname).onmouseover = function() {
                star_rate(ratings[thisy], thisx, 1);
            };
            document.getElementById(fullname).onmouseout = function() {
                star_rate(ratings[thisy], thisx, 2);
            };
        })(x, y);
    }
}

That works by passing x and y as parameters into a function, which then sets up the event handlers using the arguments rather than the outer loop's version of x and y. (I've also removed the function names in the event handler assignments above. Using a name in a function expression [as opposed to a function declaration] is problematic in some browsers, more here. Also, you'd called them both onmouseover, which probably isn't what you meant to do. :-) )

But that's not how I'd recommend doing it. It creates a new function for each element. Instead, I'd probably store the necessary information on the element itself as an attribute, and use a common function for all of this. That's what HTML5's data- prefix is for (and it works now, today, even though technically not valid). Something vaguely like this:

var ratings = new Array("happy", "clean");
var element;
for(y = 0; y < 2; y++)
{
    for(x = 0; x < 5; x++)
    {
        fullname =  ratings[y] + '_' + x;
        element = document.getElementById(fullname);
        element.setAttribute('data-star-x', x);
        element.setAttribute('data-star-y', y);
        element.onmouseover = handleMouseOver;
        element.onmouseout = handleMouseOut;
    }
}

function handleMouseOver() {
    star_rate(this.getAttribute('data-star-y'), this.getAttribute('data-star-x'), 1);
}
function handleMouseOut() {
    star_rate(this.getAttribute('data-star-y'), this.getAttribute('data-star-x'), 2);
}

You could even use event bubbling (since mouseover and mouseout bubble) to hook the events on the overall container rather than each element, since you're getting the data from the element. (That's sometimes called "event delegation".)

T.J. Crowder
A: 

Your question is kind of poorly written, so I am not sure what exactly you are fighting. But I think possibly your problem is that x and y are not visible from within the onmouseover call. You can solve this a number of ways, mostly involving attaching the x and y to the element so it's retrievable from within the function. One way to do this would be as follows:

var ratings = new Array("happy", "clean");
for(y = 0; y < 2; y++) 
{
    for(x = 0; x < 5; x++) 
    {
        fullname =  ratings[y] + '_' + x;

        var ele=document.getElementById(fullname);
        ele.setAttribute("data-ratings",y+","+x);

        ele.onmouseover = function onmouseover() 
        { 
            var split=this.getAttribute("data-ratings","").split(",");
            var y=split[0];
            var x=split[1];
            star_rate(ratings[y], x, 1); 
        };
        ele.onmouseout = function onmouseover() 
        { 
            var split=this.getAttribute("data-ratings","").split(",");
            var y=split[0];
            var x=split[1];        
            star_rate(ratings[y], x, 2); 
        };
    }
}
larson4
*"...But I think possibly your problem is that x and y are not visible from within the onmouseover call..."* Yes they are, the event handler functions are closures that close over those variables. They just don't have the *values* he's expecting them to have. (By the time the handler is called, `y` is always 2 and `x` is always 5, barring other code changing them after the quoted code completes.) http://blog.niftysnippets.org/2008/02/closures-are-not-complicated.html
T.J. Crowder