2

This seems like such a straight-forward thing to do, but I can't find a jQuery function to handle this.

For example,

$('div').show().sayHi()

function sayHi(obj) {
    obj.html('hi')
}

sayHi() is not a jQuery function so it can't be called in this context. You would need to call it like:

var $div = $('div').show()
sayHi($div)

But I want it as part of the chain, mostly because it looks nicer.

Solution:

Answer from Barmar best answers this specific question, but my implementation was a more reusable option, as shown in my answer below.

3 Answers 3

5

You can add your own jQuery method, by defining it as a property of $.fn. So you can write:

$.fn.sayHi = function() {
  this.html('Hi');
  return this;
}

$("#click").click(function() {
  $("#foo").show().sayHi();
});
#foo {
  display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="click">Click me</button><br>
<div id="foo"></div>

By convention, jQuery methods that don't return information related to the object should return this so they can continue to be chained.

Sign up to request clarification or add additional context in comments.

7 Comments

Thank you for your answer. I am interested to know why you prefer this implementation over my own? They are obviously quite similar. I personally prefer my own because it is reusable, and allows for any function to be called without creating a load of specific implementations. @ChiralMichael same question to you.
The question asked how to use .sayHi() in the chain, this shows how to do it that way.
Fair enough. :)
Also, your solution doesn't generalize well to functions with additional arguments. Consider if you wanted .sayMessage("hello there")
Yeah that's a good point. It could be extended to something like this: jsfiddle.net/vrd5boxj/1 but maybe that's getting a little less readable at that point.
|
1

You are mistaken in what you are asking. By syntax, obj.foo().bar() means: call foo on obj. Now, take the return value of that call and call bar on that. Where you have likely seen this sort of thing in JavaScript is in JQuery's Promise pattern. A promise object is instantiated with a method to call and can chain with further methods via it's done/then/fail methods. It is usually used when delaying (deferring) execution, but CAN be a nice way generically extend certain types of operations with extended behaviors (timeouts, retrys, etc).

USE WITH CAUTION. Most situations don't call for this, nor will your fellow devs understand what you are doing, unless you keep things well encapsulated.

6 Comments

I don't think I am mistaken, and am familiar with promises. I want to pass the return from .show() into the function .sayHi(). .show() will return the modified jQuery object which will be passed into custom, and then sayHi. It is the equivalent of calling $('div').show(); sayHi($('div'));
The idea of chaining method calls long predates the introduction of Promises in jQuery.
@Pointy: You point addresses nothing about my answer. I in no way suggest anything about the originality of "chaining method calls". Rather I commented on where jonofan was likely to encounter pipelining in javascript. Many JQuery methods also return a JQuery objects and can be useful for pipelining, but jonofan would need to muck about with prototypes and I am even less inclined to recommend that, regardless of whatever cavalier attitudes the js community has on the matter (I leave that for plugins). I appreciate clarifications, but your response was neither clear nor correct.
You don't have to "muck about with prototypes" to create a new jQuery method any more than the OP's own answer already does. It's an extremely common thing to do in codebases that use jQuery. I mean, you're right about Promises being somewhat involved (though jQuery Promises are really an inferior implementation compared to Promise/A+), but that really just doesn't have anything to do with the code the OP both asked about and proposed as a solution.
@Pointy: I have a suspicion that we are talking past each other, probably answering different questions. I would enjoy seeing your suggestion. Correction: I'll take Barmar's answer below.
|
1

Create a custom jQuery function which accepts a function to call, and calls it. Returning this will allow further chaining to take place after the custom function.

This solution uses Function.prototype.apply() to allow for an arbitrary number of parameters to be passed in. (Added on suggestion from Barmar.)

$.fn.custom = function(f) {
  var fnToCall = f; //array shift below makes our param undefined
  [].shift.apply(arguments); //first param is the function, which don't want to pass 
  return fnToCall.apply(this, arguments);
}

$('#btnRun').click( () => {
  $('div').empty()
          .custom(sayHi, "test", "ing")
          .custom(sayHi, ' ', 'a', ' ', 'lot ')
          .custom(sayHi, 'of', ' params ')
})


function sayHi(...args) {
    var $obj = $(this)
    $obj.html($obj.html().concat(...args))
    return this
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id='btnRun'>Test </button>

<div>
</div>

This was the solution I implemented in the end, because I wanted a reusable function. It doesn't exactly answer the question, which is why it is not marked as answer.

2 Comments

I would choose a name other than .call(). That'll be confusing, as there's already a .call() method on the Function prototype.
@Pointy, excellent point. I have updated to .custom() which is not in the Function prototype.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.