I am adding / removing a class from an element’s classList based on a variable’s truthiness. However, I’m doing it in what appears to be an obtuse way:
if (myConditionIsMet) {
myEl.classList.add("myClass");
} else {
myEl.classList.remove("myClass");
}
Is there a way in which I could make this more sexy and dynamically call the add / remove chained function for example with a conditional operator such as:
myEl.classList.{myConditionIsMet ? add('myClass') : remove('myClass')};
The above is pseudocode, of course, and I would like as plain JS as possible.
There’s a toggle method on .classList which takes a second argument (force).
This boolean argument essentially takes a condition that adds the class if true, and removes the class if false.
myEl.classList.toggle("myClass", myConditionIsMet);
Your pseudocode js
myEl.classList.{myConditionIsMet ? add('myClass') : remove('myClass')};
can be translated to actual js
myEl.classList[myConditionIsMet ? 'add' : 'remove']('myClass');
which is not particularly readable, but does exactly what you described.
For readability, I would look at the toggle method.
Related
There are quite a number of jQuery methods that accept functions instead of values as parameters. .append() is an example of that. Instead of writing:
something.append( '<div></div>' );
one might write:
something.append( () => '<div></div>' );
That's... nice. But I'm wrecking my mind trying to come up with a use case for this. Why would I want to do that? Does this enable something that would not otherwise be possible? Or does it at least drastically shorten or beautify certain bits of code?
Just to quickly add the purpose of this question: I'm writing a JS library that doesn't operate on HTML but still might as well have an API that's similar to jQuery's. So now I'm trying to figure out what to copy and what not to.
EDIT:
One use case is to index elements based on their position in the matched set. (Thanks to #Satpal and #JasonSmith!)
A second use case is to conditionally add content - as long as there's no condition that requires not to add content. (Thanks again to #JasonSmith)
Are there other practical use-cases? Does this get used often?
In .append(fn) method. With in the function, this refers to the current element in the set. which lets us to manipulate the content to be appended.
Here is an example.
$('p').append(function(){
return $(this).index();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p></p>
<p></p>
<p></p>
<p></p>
OR
$('p').append(function(){
return $(this).next('a');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p></p>1
<p></p>2
<p></p>3
<p></p>4
#Satpal provided an excellent example of one use case using the append function in jQuery. In more general terms, however, I look at it this way: if you are creating an API method capable of operating on a set of objects, then accepting a function as an argument for that API method allows the user to vary the behavior of the API according to the unique properties of each object in the set. For example, suppose we have a collection of elements like this:
<li>100</li>
<li>1000</li>
<li>150</li>
Suppose also that we have a hypothetical API method called myAPI.colorize(). If the colorize function accepts only a string, then all items in the set will be made the same color
mySet.colorize('red');
If, on the other hand the colorize method also accepts a function as an argument, then the developer can dynamically colorize without being required to break the set into constituent parts, like this:
mySet.colorize(function(currentElement) {
return currentElement.text == '1000' ? 'green' : 'red';
});
Or, if our hypothetical API binds the this reference the way jQuery does, then we could make our code even simpler:
mySet.colorize(function() {
return this.text == '1000' ? 'green' : 'red';
});
Of course this is a somewhat contrived example, but I believe it illustrates the design point in question without getting too stuck on a specific feature of jQuery.
I use the following jQuery structure a lot so I want to write it shorter (EDIT: the addClass and removeClass are EXAMPLE functions, I want to know a general ternary way to apply different functions to an object, so do not tell me about toggleClass which doesn't even work like below code):
if(something){
obj.addClass('class');
}else{
obj.removeClass('class');
}
I want to write it in a single line, so I would like to know how to apply jQuery functions conditionally. Something like the following using a ternary operator, only this doesn't work yet:
$[something?'addClass':'removeClass'].apply(obj,'class');
This is easily done in regular javascript but how do I structure the above correctly to work in jQuery?
EDIT: I am not searching for two separate calls such as:
something ? obj.addClass('class') : obj.removeClass('class');
Just put it to equal the something, if it is true it will triger otherwise wont triger.
$( this ).toggleClass( "class" ); = something;
What about writing a helper function?
function ternary(object, condition, a, b) {
var method = condition ? $.fn[a] : $.fn[b];
var args = arguments.slice(4);
return method.apply(object, parameters, args);
}
Then you could do
ternary(obj, something, 'addClass', 'removeClass', 'my-class-name');
ternary(obj2, somethingElse, 'slideUp', 'slideDown');
Given jQuery's philosophy of write less, do more, I'm always surprised when I see this:
$(this).prop('checked')
… instead of this:
this.checked
Looking at the latest jQuery source, prop() provides convenience for these two gotchas:
$(elem).prop('for') is equivalent to elem.htmlFor.
$(elem).prop('class') is equivalent to elem.className.
It also normalizes tabIndex to:
0 for tabbable elements without a tab index.
-1 for non-tabbable elements.
prop() is certainly useful for setting properties for multiple elements at once, and for chaining properties on a single element.
But is there any advantage (other than idiomatic) to use prop() to set or retrieve a single property on a single element except when normalizing tabIndex – specifically when you have a reference to the element (such as this in a callback)?
.prop as a getter has no real advantage, in fact, it is less performant than directly accessing the property.
The real utility of .prop is when used as a setter.
If you read the DOC, there is 3 way of setting something with .prop.
.prop(prop, value)
The first way has no advantage for a single element(except maybe if there is compatibility issue).
In fact this.check = true; is the same as $(this).prop('checked', true), but faster.
If you have a set of element though, there is an advantage. You don't have to manually loop all elements, jQuery does it for you.
.prop({prop : value[, prop : value, ...]});
The second way is useful when you have multiple properties to change. Instead of listing every properties you want to change like that :
this.prop1=true;
this.prop2=true;
this.prop3=true;
this.prop4=true;
You can pass an object like that :
$(this).prop({
prop1 : true,
prop2 : true,
prop3 : true,
prop4 : true
});
.prop(prop, callback)
The third way is in my opinion my favorite one. Using a callback function allow you to set every element individually on a set of condition. The callback receive 2 arguments: the index and the old value.
A good example of the use of a function is to reverse the state of every checkbox:
$('checkbox').prop('checked', function(_, old){
return !old;
});
Sometimes I'd like to add class in chain, under some condition. What value would be semantically most appropriate to add no class?
Example:
$(".element").doSomething().addClass(condition ? "special-class" : undefined).doSomethingElse();
Or:
$(".element").doSomething().addClass(condition ? "special-class" : null).doSomethingElse();
Use $.toggleClass() instead:
$(".element").doSomething().toggleClass("special-class",condition).doSomethingElse();
As ruakh mentioned it, there is a difference. If condition is falsy, it will actually remove the class if it was present before. With your logic, the class can only be added, not removed.
jQuery checks input parameter like this:
typeof input == "string"
so either null or undefined will behave the same way
How do I use hasClass so it works as doesNotHaveClass? In other words, rather than looking to see if it is a specified class, looking to see if it is NOT a specified class. Can I use an exclamation point or something like that?
Yes, you can.
if (!$('element').hasClass('do-not-want')) {
// This element does not have the .do-not-want class
}
However if you're trying to use selectors to find all the items that don't have a class, perhaps try this:
// find all divs that don't have "badClass" class
$('div').not('.badClass').each(function(){});
if (!$('a').hasClass('xyz')){
...
}
Yes, you can
As per the jQuery documentation:
The .hasClass() method will return true if the class is assigned to an element, even if other classes also are.
Since the function returns a boolean you can use exclamation point to negate the result.
You can check if the return is false:
if($(element).hasClass("class") === false) {...}