views:

1155

answers:

7

I grabbed this code form JCarousel and just trying to understand these lines below. I'm new to jQuery and not that great at JavaScript so I am not sure what is jQuery and which is JavaScript below

this.buttonNext[n ? 'bind' : 'unbind'](this.options.buttonNextEvent, this.funcNext)[n ? 'removeClass' : 'addClass'](this.className('jcarousel-next-disabled')).attr('disabled', n ? false : true);
this.buttonPrev[p ? 'bind' : 'unbind'](this.options.buttonPrevEvent, this.funcPrev)[p ? 'removeClass' : 'addClass'](this.className('jcarousel-prev-disabled')).attr('disabled', p ? false : true);

It's setting some of the css to set state and either enabling or disabling the button that is in a but I want to modify this once I really understand it. I just can't make out exactly what it's doing 100%.

Trying to understand things such as [n ? 'bind' : 'unbind'] and just the chaining here also. There's a lot going on in those 4 lines.

The code comes from this plug-in: http://sorgalla.com/projects/jcarousel/

+1  A: 
[n ? 'bind' : 'unbind']

Is an if statement, which can be rewritten as

if (n) // if n is true
{
   'bind';
}
else
{
   'unbind';
}

So if n is true, it would evaluate like this

this.buttonNext.bind((this.options.buttonNextEvent, this.funcNext))

because [ ] notation is the same as . notation.

buttonNext[bind] is the same as buttonNext.bind

To summarize what you posted, it checks the states of variables (n and p) which holds the state of the button. If it is enabled, then when activated it disables it, adds the disabled classes, etc. If it's disabled, it sets it to enabled and removes the disabled class.

Ian Elliott
A: 

These two lines check if there are any "next" or "prev" items to display and enables/disables the buttons accordingly by adding disabled jcarousel-next-disabled(enabled) and setting the disabled attr to true/false.

Alexandru Plugaru
+6  A: 

The first part to understand is symbol resolution. Javacript supports both dot-notation and bracket-notation.

Consider opening a new window.

window.open()

This is dot-notation in action. you're telling the interpreter that "open" can be found on "window". But there's another way to do this

window['open']()

Same thing, but with bracket notation. Instead of using the symbol name directly, we're using a string literal instead. What this means is that by using bracket-notation for symbol resolution, we can do it in a dynamic way, since we can choose or build strings on the fly, which is exactly what this snippet does.

this.buttonNext[n ? 'bind' : 'unbind'](...);

Is analagous to

if ( n )
{
   this.buttonNext.bind(...);
} else {
   this.buttonNext.unbind(...);
}

If you don't recognize the ?: syntax, that's the conditional operator, or conditional expression

[expression] ? [valueIfTrue] : [valueIfFalse]

This is extremely often erroneously called the "ternary operator", when in fact it just a ternary operator (an operator with three operands). The reason for this is because in javascript (and most languages) is the only ternary operator, so that description usually flies.

Does that help? is there anything else you need cleared up?

Peter Bailey
While I see what's going on in pieces, putting it altogether seems like a mess in JCarousel.
CoffeeAddict
+1  A: 

These lines are in the middle of a method that takes two parameters.

n // whether to show the next button
p // whether to show the previous button

Either of these buttons can be null or undefined, which causes jCarousel to look at other factors, like whether or not the carousel is locked.

Take a look at this:

  lock: function() {
      this.locked = true;
      this.buttons();
  },
  unlock: function() {
      this.locked = false;
      this.buttons();
  }

If you look a few lines up from your two lines, you'll see that this.locked is taken into consideration for setting n and p when they are not passed in as true.

Let's break apart one of the lines a bit:

this.buttonNext[n ? 'bind' : 'unbind'](this.options.buttonNextEvent, this.funcNext)[n ? 'removeClass' : 'addClass'](this.className('jcarousel-next-disabled')).attr('disabled', n ? false : true);

bindMethod = n ? "bind" : "unbind"; // bind if n is true; otherwise unbind
this.options.buttonNextEvent // defaults to "click", can be changed in the options
this.funcNext // function() { self.next(); }; // self is a local available to the closure

changeClass = n ? "removeClass" : "addClass" // same as above
this.className("jcarousel-next-disabled") // adds -vertical or -horizontal to the class

toDisable = !n // Effectively

So, one way this might work would be:

this.buttonNext.bind("click", function() { self.next(); }).removeClass("jcarousel-next-disabled-horizontal").attr("disabled", false);

And as other pointed out, JavaScript supports both bracket and symbol notation. The following two are identical:

x.y
x["y"]

Note that bracket notation is a bit more flexible:

x.omg-omg // Illegal
x["omg-omg"] // Legal

Also note that methods are just property lookup plus invocation. The following two are identical:

x.omg()
x["omg"]()

Which means you can also do this:

x[someVariable]()

Tada! Hope that helped.

Yehuda Katz
A: 

The conditional operation

n ? 'bind' : 'unbind'

gets you either the string 'bind' or 'unbind', passing that string to the [] operator gets you either the jQuery bind or unbind method. Following that result with the () invokes the method. In effect, that first part is like:

if (n) {
    this.buttonNext.bind(this.options.buttonNextEvent, this.funcNext);
}
else {
    this.buttonNext.unbind(this.options.buttonNextEvent, this.funcNext);
}
if (p) {
    this.buttonPrev.bind(this.options.buttonPrevEvent, this.funcPrev);
}
else {
    this.buttonPrev.unbind(this.options.buttonPrevEvent, this.funcPrev);
}

Both the bind and unbind method return the jQuery set on which they were invoked. In this case, they will return this.buttonNext and this.buttonPrev, respectively. Following that with yet another [] operator and passing that operator the string 'removeClass' or 'addClass' gets you the removeClass or addClass jQuery method. In effect, you now have this:

if (n) {
    this.buttonNext.bind(this.options.buttonNextEvent, this.funcNext);
    this.buttonNext.removeClass(this.className('jcarousel-next-disabled')).attr('disabled', n ? false : true);
}
else {
    this.buttonNext.unbind(this.options.buttonNextEvent, this.funcNext);
    this.buttonNext.addClass(this.className('jcarousel-next-disabled')).attr('disabled', n ? false : true);
}
if (p) {
    this.buttonPrev.bind(this.options.buttonPrevEvent, this.funcPrev);
    this.buttonPrev.removeClass(this.className('jcarousel-prev-disabled')).attr('disabled', p ? false : true);
}
else {
    this.buttonPrev.unbind(this.options.buttonPrevEvent, this.funcPrev);
    this.buttonPrev.addClass(this.className('jcarousel-prev-disabled')).attr('disabled', p ? false : true);
}
dgvid
A: 

IMHO, that code is completely unreadable as you would agree.

As Peter wrote, you need to know that JavaScript method could be called using DOT notation or BRACKET notation. Also, jQuery supports chaining.

Once you know these two things, here's how the code break downs.

this.buttonNext[n ? 'bind' : 'unbind'](this.options.buttonNextEvent, this.funcNext)[n ? 'removeClass' : 'addClass'](this.className('jcarousel-next-disabled')).attr('disabled', n ? false : true);

The above line does three things. Binds/Unbinds event, add/removes class and enables/disables the 'buttonNext'.

-1. Bind/unbind step

this.buttonNext[n ? 'bind' :'unbind']
        (this.options.buttonNextEvent, this.funcNext);

You are calling the bind, unbind depending upon whether n is true or false. More importantly, the bind method call will return 'this.buttonNext'.

-2. addClass/removeClass step

this.buttonNext[n ? 'removeClass' : 'addClass']
    (this.className('jcarousel-next-disabled'))

Again, based on 'n', it will either call addClass or removeClass method passing it the appropriate class name. You get the same 'this.buttonNext' object back.

-3. Finally, enable/disable button step

this.buttonNext.attr('disabled', n ? false : true);

Disabling/enabling the button based on whether n is true or false.

Even though I love chanining, I think chaninig was misused in this code.

SolutionYogi
A: 

Ok guys, I'd like to bring my share to this topic, and tell you about the easiest way to disable clicked dialog button. Here goes:

$("#dialog-selector").dialog({
    title: "Dialog",
    // Other options
    buttons: {
        "Ок": function(e) {
            $(e.currentTarget).attr("disabled", true);
        }
    }
});
TempleOfGod