0

Normally the execution of a setTimeout() method is aborted by a clearTimeout() method that is outside of the setTimeout() method, but in my situation I need to abort the execution of a setTimeout() loop within the loop itself if a certain event occurs during the designated "waiting period".

In my code shown below, the user gets 500 milliseconds to activate Code A. If he fails to activate Code A within the time frame, Code B will be executed as a fallback. Within Code A I have marked two places: 1) the place to stop the timeout and 2) the place where I wish to exit the function.

My jsFiddle is here.

A copy of my JavaScript and HTML codes is shown below:

HTML

<table id="headMenu">
    <tr>
        <td id="head1">Item 1</td>
        <td id="head2">Item 2</td>
        <td id="head3">Item 3</td>
    </tr>
</table>
<table id="subMenu">
    <tr>
        <td>Dynamic Content!</td>
    </tr>
</table​​​​​​​​​​​​​​​​​​​​​​​​​​​​>​​​

JavaScript

a = 500;
document.getElementById("head1").onmouseover = function(displayMenu) {
    document.getElementById("subMenu").innerHTML = "<tr><td>Item A</td><td>Item B</td><td>Item C</td></tr>";
    document.getElementById("head1").onmouseout = function(getScroll) {
        setTimeout(function() {
            document.getElementById("subMenu").onmouseover = function(breakTimeout) { // **Code A**
                a = 10000;
                // **Stop timeout.**  Now never execute Code B.
                document.getElementById("subMenu").onmouseout = function(endFunction) {
                    document.getElementById("subMenu").innerHTML = '<tr><td>Content is Dynamic!</td></tr>';
                    // **Exit function here immediately**
                }
            }
            if(a==500){
            //**Code B**:  Only execute if **Code A** never executed within time frame
                document.getElementById("subMenu").innerHTML = '<tr><td>Dynamic Content!</td></tr>';
            }
        }, a)
    }
}​

I hope the concept of my design is also evident. If my code and description is not clear enough, I'll be glad to clarify further questions.

Thanks a lot and +1 to anybody who can get the answer!

zdebruine
  • 3,687
  • 6
  • 31
  • 50
  • 1
    Can you explain - with specific reference to the HTML elements on your page - what you want? – Anthony Grist Jun 08 '12 at 13:19
  • When mouseover id="head1", getinnerHTML of id="submenu" to display the Item A Item B Item C menu. Onmouseout of "head1", hide submenu 500 milliseconds later UNLESS mouse has moved over id="submenu" (i.e. scrolling through that menu). If true, never hide submenu until mouse leaves submenu. If true, change submenu.innerHTML back to "Dynamic Content" immediately. – zdebruine Jun 08 '12 at 13:21

2 Answers2

1

Your original premise was flawed. The body of the function passed to setTimeout() doesn't execute until after the time has elapsed, so the code you wanted to stop the timeout wouldn't be executed until it was too late. I've modified your code to use a standard clearTimeout() which should do what I think you want.

var a = 500, head1 = document.getElementById('head1'), subMenu = document.getElementById('subMenu'), timeout;

head1.onmouseover = function(displayMenu) {
    subMenu.innerHTML = '<tr><td>Item A</td><td>Item B</td><td>Item C</td></tr>';
    head1.onmouseout = function(getScroll) {
        subMenu.onmouseover = function(breakTimeout) {
            clearTimeout(timeout);
            subMenu.onmouseout = function(endFunction) {
                subMenu.innerHTML = '<tr><td>Content is Dynamic!</td></tr>';
            };
        };
        timeout = setTimeout(function() {
            document.getElementById("subMenu").innerHTML = '<tr><td>Dynamic Content!</td></tr>';
        }, a);
    };
};

Working DEMO

Anthony Grist
  • 38,173
  • 8
  • 62
  • 76
  • Do you have any idea why I can't scroll across Item A, Item B, or Item C? – zdebruine Jun 08 '12 at 13:42
  • 1
    @wagtail Made a minor edit to the code and the jsFiddle. I wasn't passing `a` to the `setTimeout()` call, so the function was just executing automatically. I've also increased the delay from half a second to two seconds in the fiddle, just so it's a bit more obvious. – Anthony Grist Jun 08 '12 at 13:42
  • Yes, the timing is very nice! It's great code, I just wish I could scroll through all of submenu before it changes to "Content is Dynamic!" – zdebruine Jun 08 '12 at 13:44
  • I'm still stuck, I can't figure out why it disappears when I leave just one of . – zdebruine Jun 08 '12 at 13:58
  • @wagtail It's due to event bubbling. When the `` elements fire a `mouseout` event, that also bubbles up to the table itself, so its event handler fires. Not sure what to do about that, though. – Anthony Grist Jun 08 '12 at 14:07
0

You can use a global variable to store the return value of setTimeout()

window.myTimeout = setTimeout(function() {
    // ...
}, a);

You can then clear the timeout from any context (as long as window.myTimeout isn't modified) like this:

clearTimeout(window.myTimeout);

Note: The "window" part is optional. It's just a convention that I personally use to make it easy to identify global variables, especially if the code is complex/huge.

Jeff G
  • 11
  • 2