Javascript doubt...

Teensweb

New Member
Messages
352
Reaction score
1
Points
0
Hi everyone I am trying to use a jquery pluggin(lavalamp) for one of my new sites
and here is the code:
Code:
(function($) {
$.fn.lavaLamp = function(o) {
    o = $.extend({ fx: "linear", speed: 500, click: function(){} }, o || {});

    return this.each(function() {
        var me = $(this), noop = function(){},
            $back = $('<li class="back"><div class="left"></div></li>').appendTo(me),
            $li = $("li", this), curr = $("li.current", this)[0] || $($li[0]).addClass("current")[0];

        $li.not(".back").hover(function() {
            move(this);
        }, noop);

        $(this).hover(noop, function() {
            move(curr);
        });

        $li.click(function(e) {
            setCurr(this);
            return o.click.apply(this, [e, this]);
        });

        setCurr(curr);

        function setCurr(el) {
            $back.css({ "left": el.offsetLeft+"px", "width": el.offsetWidth+"px" });
            curr = el;
        };

        function move(el) {
            $back.each(function() {
                $(this).dequeue(); }
            ).animate({
                width: el.offsetWidth,
                left: el.offsetLeft
            }, o.speed, o.fx);
        };

    });
};
})(jQuery);
My question is quite simple, as I am not so used to jquery, can somebody please tell me what syntax to use so that I can access the setCurr() and move() functions from outside?
(say from the <script> tag in the page I include the script)
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
Assign them to globals, or to properties of a global. Assigning them to properties of window is equivalent to assigning them to global variables, but is more explicit.

Code:
(function () {
    ...
    // is 'bar' a local or a global?
    bar = function () {
        ...
    }
    // 'baz' is a global, no question
    window.baz = function() {
        ...
    }
    ...
})();

// call function 'baz' as:
baz();
 

Teensweb

New Member
Messages
352
Reaction score
1
Points
0
So are you suggesting that I declare setCurr(el) as
Code:
window.setCurr()=function(el){
.......
}
so that I can use it anywhere? But then I get an error that setCurr() is undefined.
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
window.setCurr()=function(el){...} will call window.setCurr, then attempt to assign an anonymous function to the result, which isn't a valid operation in JS. Leave out the parentheses. Take a closer look at my previous code sample.
 

Teensweb

New Member
Messages
352
Reaction score
1
Points
0
Sorry the parentheses was a typo, i hadn't included the parentheses in my code and firefox still says setCurr is undefined when I try to call it from the html page.
 
Last edited:

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
Do you have a link to a live page?

Did you call lavaLamp before trying to call setCurr?

Taking a closer look at the original source code, there's a problem with what you're trying to do: each element that lavaLamp is called on (each lava lamp) defines its own setCurr. If you try to store setCurr in a global, the last one defined overrides all the others, which is the main problem with globals. If there's only one lava lamp, this isn't an issue, but if there's more than one, only the last lava lamp to be defined will work, and the previous lava lamps will interfere with the operation of the last. Since the upvalues in setCurr are $back and curr, the consequence in this case are that the $back for the last lava lamp will be moved, and the element will be set to the current element for the last lava lamp.

To fix, either find a way to associate each object (i.e. lava lamp) with its setCurr or define a single setCurr.
 
Last edited:

Teensweb

New Member
Messages
352
Reaction score
1
Points
0
Yeah I found the problem I forgot to call lavalamp before using setCurr(), it works fine now, Thanx misson.
But as for the problem you mentioned with globals, I am using only one instance of lavalamp on a page, but still I want to understand what you said.
Do you mean that I have two lavalamps-two navigation menu's ( I guess you know what the lavalamp thingy is, if not see this ) then there might be trouble? Like, if I set the curr in one lavalamp, it will reflect on the other too?
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
Do you mean that I have two lavalamps-two navigation menu's [...] then there might be trouble? Like, if I set the curr in one lavalamp, it will reflect on the other too?
Yes, there will be trouble. In particular, if you call the global setCurr, it will only affect the last lava lamp, even though you may be trying to call it on a different lava lamp. The $li.click handlers will still work properly, since they call the local setCurr.

There's a potential gotcha in the fix due to how jQuery works. When you call $, it creates a collection that functions as a wrapper around HTML elements. Every time you call $, you'll get a different wrapper, even if you use the same selector or call it on the same element.

HTML:
<div class="foo"><span id="Thing" /></div>
<script type="text/javascript">
// all these are false
console.log($('#Thing') == $('.foo > span'));
console.log($('#Thing') == $('#Thing'));
var thing = $('#Thing');
console.log($(thing) == $(thing));
</script>

This means you can't store setCurr as a property of the jQuery lava lamp objects. Instead, you can store it as a property of the underlying HTML elements, which are bound to this inside the function passed to each and passed as the second argument.

Code:
(function($) {
    $.fn.lavaLamp = function(o) {
        o = $.extend({ fx: "linear", speed: 500, click: function(){} }, o || {});

        return this.each(function(i, element /* note: this == element */) {
            ...
            this.setCurr = setCurr;
        });
    };
})(jQuery);

To call setCurr for a given lava lamp, you'll need a reference to the HTML element, which you can do by getting a jQuery object, then taking the n-th element:
Code:
// set the current element of #MainMenu to its 3rd item
$('#MainMenu')[0].setCurr(  $('> li', $('#MainMenu'))[2]  );

// set the current element of the 3rd submenu of #MainMenu to its 1st item
$('#MainMenu > li:nth-child(3) > .menu')[0].setCurr(  $('#MainMenu > li:nth-child(3) > .menu > li:nth-child(1)')[2]  );

// set the current element of the 5th menu to its 4th item
$('.menu')[4].setCurr(  $('.menu > li')[3]  );
 
Last edited:

Teensweb

New Member
Messages
352
Reaction score
1
Points
0
Wow, thanx misson, that was really helpful! It solved some of the numerous problems that I faced with js and jq in a single post, but don't worry, there are still a lot left(lol)!
BTW, the thread maybe closed. X10's great...
 
Top