andrew
andrew

Reputation: 9583

Does jQuery have a generic callback to avoid breaking chains?

Sometimes I find myself quite happily chaining my way through a set of jQuery functions until I hit a condition.

Then I have to break my chain up into separate chunks, apply variables to each one and rethink the process

Consider the following snippet:

var $options = $('#options');

$options.on('click', '.addoption', function () {
	    $(this)
		    .parent()
		    .clone()
		    .find('input')
		    .val('')
		    .parent()
		    .appendTo($options)
		    .find('label')
		    .html('');
	    $(this).remove();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="options">
            <div>
                <label class="label">options</label>
                <input name="option[]"/> 
                <button class="addoption" >+</button>
            </div>
        </div>

Suppose I wanted to add a class to the input depending on a certain condition.

I could do something like:

...
 .find('input')
 .val('')
 .addClass(myCondition?'myClass':'')
 .parent()
...

But this would involve an unnecessary call to .addClass() if myCondition was false, but moreover using a ternary operator wouldn't be practical in all situations.

What would be more convenient is something like:

...
 .find('input')
 .val('')
 .call(function(jQueryObject){
    if(myCondition){
        jQueryObject.addClass('myClass')
      }
  })
 .parent()
...

Where call is a method that runs a callback which receives the jQuery object itself as a parameter and then returns the jQuery object.

This would allow operations to be carried out on the object depending on conditions and then continue on with the unbroken chain.

I've read the documentation carefully but did not find any methods that look like they might do this.

This is something I might be able to implement myself by extending the jQuery object but I didn't wan to set about reinventing the wheel if such functionality already exists

Upvotes: 2

Views: 117

Answers (3)

guest271314
guest271314

Reputation: 1

Try utilizing .toggleClass( className, state ) , where state would be condition , Boolean

alternatively

$.fn.doStuff = function(condition, method, args, that) {
  if (condition) this[method](args);
  return that || this
}

Upvotes: 0

Ram
Ram

Reputation: 144689

There is no such method. The jQuery way of testing a condition is using the filter method which as the name suggests, filters the collection. Since a jQuery object is a collection of elements, the method is useful for checking properties of each individual element and not for a general criterion. After filtering and calling the desired methods you can get the pre-filter collection using the .end() method.

$object
  .filter(function() {
     return true || false;
  })
  .addClass()
  .end()
  ...

If you want to test a condition and keep the jQuery object, you can cache it and use an if statement.

var $object = ...
              .find('input')
              .val('');

if ( condition ) {
   $object.addClass('class');
}

However, if you prefer to use a method instead of caching the object and using an if statement, you can define a method that works like the filter method but it filters the collection itself and not the collection's elements.

/**
  This method uses the jQuery `slice` method for slicing the collection.
  If the passed condition is a truhy value it returns the same collection,
  otherwise it returns the same collection without the elements. Using the
  `slice` is necessary for getting the pre-filter collection using the `end` method.
  @param {Boolean} condition
  @return {Object} the same jQuery object 
**/
$.fn.filterAll = function(condition) {
    return condition ? this.slice(0) : this.slice(0, 0);
};

$object
  .filterAll(condition)
  .addClass('foo')
  .end()
  ...

In this case, you could also use the addClass callback function. The callback function is executed once for each element in the collection. When null is returned, jQuery doesn't modify the element's className property.

...
 .find('input')
 .val('')
 .addClass(function() {
    // `this` keyword here refers to each element in the collection
    return condition ? 'class' : null;
  })
 .parent()
...

Upvotes: 2

yarn
yarn

Reputation: 89

You can use the .each function and pass a callback into it to do what you need.

...
.find('input')
.val('')
.each(function(jQueryObject){
if(myCondition){
  jQueryObject.addClass('myClass')
}
...

Upvotes: 1

Related Questions