I have a list of items in a page that must be hidden in sequence, but just after the previous item has been totally hidden.
I made the following code, where I create a big string inserting the callbacks inside the previous callbacks and later use eval to execute the effects, but despite the code is working fine as expected, I'm totally sure that's not the best way to do this.
// get items to hide
var itemsToHide = jQuery(".hide");
// function responsible to hide the item
var hideItem = function (item, callback) {
jQuery(item).hide(100, callback)
};
// declare an empty function, to be the first to be called
var buff = function(){};
for (var i = 0; i < itemsToHide.length; i++) {
// put the previous value of buff in the callback and assign this to buff
buff = "function(){hideItem(itemsToHide[" + i + "], " + buff + ");}";
}
// execute the effects
eval("(" + buff + ")()");
Any suggestion on how to accomplish this effect using recursion, without the "evil" eval?
In this case you know the duration of the effect, so you can do as others suggested.
However you might still want to know how to achieve the same using a more functional style, using a simple recursion.
So here I show you a way to do that.
<script src="http://code.jquery.com/jquery-latest.pack.js"></script>
<script type="text/javascript">
$(function() {
var items = jQuery(".to-hide");
(function hideRec() {
if (items.length == 0) {
window.alert("The end.");
return;
}
var toHide = jQuery(items[0]);
items = items.slice(1);
toHide.hide("100", hideRec);
})();
});
<script>
<ul>
<li class="to-hide">...</li>
<li class="to-hide">...</li>
<li class="to-hide">...</li>
<li class="to-hide">...</li>
<li class="to-hide">...</li>
<ul>
We first obtain, from jQuery, an array containing the objects we want to-hide.
Then we create a named anonymous function that will be executed right after its definition -- it's the (function() { ... })(); pattern. Even if it is an anonymous function, we give it a name so that we are able to easily call it recursively.
Note that you can achieve the same thing without giving an anonymous function a name -- which may sound a little strange if you don't understand how JavaScript deals with scope -- with the more obscure version:
(function() { // Anonymous function without a name
if (items.length == 0) {
window.alert("The end.");
return;
}
var toHide = jQuery(items[0]);
items = items.slice(1);
toHide.hide("100", arguments.callee); // Recursive call to anonymous function
})();
This time we used the fact that arguments.callee represents the function itself -- so no need to give an anonymous function a name.
The whole magic is inside this recursive anonymous function -- that is a closure.
The hideRec anonymous function captures the items array. After checking that there's still something inside, it will remove the first element and store it in the local toHide variable (properly wrapped with jQuery).
At the end, it uses jQuery to hide the element, and passes this anonymous function as the callback -- jQuery will call it again once it has finished the effect.
I hope this is clear enough.
Good luck!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With