1

I'm new to javascript/jquery and here's the example code I need help with:

function add(text) {
  $(this).replaceWith('<label>'+text+'</label>');
}

var label = 'Added';
$('#myDiv').append($('<button type="button">Add</button>').click(function() {
  add.call(this, label);
}));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="myDiv"></div>

Is there a "better" way of setting the click callback here?

If the add function did not have a text argument, I could have easily used .click(add) and the button will be bound automatically as this.

But with the argument, I can't bind text without having to set the value of this too i.e. .click(add.bind(this, label)) would be wrong as this is set to the global context.

Thoughts?

zhaomin
  • 381
  • 3
  • 13
  • 3
    Have a look at [`.on( events [, selector ] [, data ], handler )`](http://api.jquery.com/on/) and its `data` parameter. – Andreas Jul 30 '16 at 07:53
  • @Andreas –I was thinking of [`jQuery( html [, ownerDocument ] )`](http://api.jquery.com/jQuery/#jQuery-html-attributes) – Rayon Jul 30 '16 at 07:54
  • @Andreas: That (with a bit more detail and example) would make a very good "here's the jQuery way" answer. – T.J. Crowder Jul 30 '16 at 07:56
  • @Andreas: Looks like a duplicate to me, good find. I'll move my answer there, surprisingly there's no "curry" answer there that I see. – T.J. Crowder Jul 30 '16 at 08:06
  • @Andreas: Oh, wait, my bad -- that question doesn't have the `this` aspect to it. – T.J. Crowder Jul 30 '16 at 08:08
  • 1
    zhaomin - The question Andreas was referring to (since his comment was auto-deleted) was this: https://stackoverflow.com/questions/3273350/jquerys-click-pass-parameters-to-user-function – T.J. Crowder Jul 30 '16 at 08:14

1 Answers1

2

As Andreas points out in a comment, there's a solution to this that's specific to jQuery event handlers: The data argument to the on function.

More generally, though, what you're looking for is sometimes called "currying" (or "partial application;" purists tell me one of them is technically incorrect but I can never remember which).

I have a function I use for that which I add to Function.prototype; it looks like this (see comments):

(function() {
    var slice = Array.prototype.slice;

    Object.defineProperty(Function.prototype, "curry", {
        value: function() {
            // Remember the original function and the arguments we wre called with
            var f = this,
                curried = slice.call(arguments);
            // Return a new function
            return function() {
                // Our function was called, add in any arguments it was called with...
                var args = curried.concat(slice.call(arguments));
                // ...and call the original, passing along `this`
                return f.apply(this, args);
            };
        }
    });
})();

In your case, you'd use it like this:

var label = 'Added';
$('#myDiv').append($('<button type="button">Add</button>').click(add.curry(label)));

Note that your add function will be called with the value of label (as it was when we made the curry call, not as it is later), followed by any arguments that the curried function was called with (e.g., the event object).

Example:

(function() {
  var slice = Array.prototype.slice;

  Object.defineProperty(Function.prototype, "curry", {
    value: function() {
      // Remember the original function and the arguments we wre called with
      var f = this,
        curried = slice.call(arguments);
      // Return a new function
      return function() {
        // Our function was called, add in any arguments it was called with...
        var args = curried.concat(slice.call(arguments));
        // ...and call the original, passing along `this`
        return f.apply(this, args);
      };
    }
  });
})();

function add(text) {
  console.log("add called with text = '" + text + "'");
}
var label = 'Added';
$('#myDiv').append($('<button type="button">Add</button>').click(add.curry(label)));
<div id="myDiv"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875