views:

255

answers:

2
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.js"&gt;&lt;/script&gt;
<script type="text/javascript">

  function bigtosmalltriangle() {
   $(this).siblings("div.break").removeClass('triangle3').addClass('triangle1');
   setTimeout ( "smalltomediumtriangle()", 400 );
  }
  function smalltomediumtriangle() {
   $(this).siblings("div.break").removeClass('triangle1').addClass('triangle2');
   setTimeout ( "mediumtobigtriangle()", 400 );
  }
  function mediumtobigtriangle() {
   $(this).siblings("div.break").removeClass('triangle2').addClass('triangle3');
   setTimeout ( "bigtosmalltriangle()", 400 );
  }

 $(function() {
  $("span#clickhere").click(
   function() {
    /* do a lot stuff here */ bigtosmalltriangle();
    $(this).hide();
   }
  );
 });
</script>

<style type="text/css">
 .triangle1 {background:#000;}
 .triangle2 {background:red;}
 .triangle3 {background:white;}
</style>

<div><div class="break">Hello World</div><span id="clickhere">asdf</span></div>

I'm trying to get get the div.break to scroll through 3 bgcolors, but when I click on the span it has no effect. Does anyone know what I should do?

Thanks.

+1  A: 

The problem is that "this" is not bound to the span you clicked on in the bigtosmalltriangle, smalltomediumtriangle, and mediumtobigtriangle functions. You need to either pass in the element as a parameter, or set a variable that's in scope in all the functions through closures.

Parameter passing:

function bigtosmalltriangle(elements) {
    elements.removeClass('triangle3').addClass('triangle1');
    setTimeout(function() { smalltomediumtriangle(elements); }, 400);
}
function smalltomediumtriangle(elements) {
    elements.removeClass('triangle1').addClass('triangle2');
    setTimeout(function() { mediumtobigtriangle(elements); }, 400);
}
function mediumtobigtriangle(elements) {
    elements.removeClass('triangle2').addClass('triangle3');
    setTimeout(function() { bigtosmalltriangle(elements); }, 400);
}

$(function() {
    $("span#clickhere").click(
        function() {
            /* do a lot stuff here */
            bigtosmalltriangle($(this).siblings("div.break"));
            $(this).hide();
        }
    );
});

Closures:

$(function() {
    $("span#clickhere").click(
        function() {
            var elements = $(this).siblings("div.break");

            function bigtosmalltriangle() {
                elements.removeClass('triangle3').addClass('triangle1');
                setTimeout(smalltomediumtriangle, 400);
            }
            function smalltomediumtriangle() {
                elements.removeClass('triangle1').addClass('triangle2');
                setTimeout(mediumtobigtriangle, 400);
            }
            function mediumtobigtriangle() {
                elements.removeClass('triangle2').addClass('triangle3');
                setTimeout(bigtosmalltriangle, 400);
            }

            /* do a lot stuff here */
            bigtosmalltriangle();
            $(this).hide();
        }
    );
});
Matthew Crumley
it's a very messy way to do it - strager's answer is the better response.
nickf
+2  A: 

You want to call your functions with a specific "this". I asked a similar question: Call function with "this".

$(function() {
        $("span#clickhere").click(
                function() {
                        /* do a lot stuff here */
                        bigtosmalltriangle.call(this);
                        $(this).hide();
                }
        );
});

I think because of closures (see Matthew Crumley's answer) the callback functions themselves don't need to be modified, because setTimeout keeps the "scope." I don't know Javascript enough to remotely guarantee that, though. If I am wrong, simply perform the .call(this) trick for the callback functions as well.

strager
The callback functions would need to be modified, because when setTimeout calls them, "this" will refer to the global scope (i.e. window). I don't see an advantage to using "this" instead of passing the elements as a parameter.
Matthew Crumley