Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jquery to test if $(this) does not have a specific class

Tags:

jquery

if ($(this).hasClass('white')) {console.log('white');};

equates to true and prints to the console. How do I test if it does not have the class white on the $(this) selector? I have

if ($('this:not(.white)')) {console.log('not white');};
and
if ($(this).not('.white')) {console.log('not white');};
and
several other combinations?

I know I likely should use the .not() method, and can't figure out how to use the :not selector in combination with the $(this) selector.

I would like that when the element is clicked, that I can see one true and one false statement. (it either does or doesn't have the class 'white')

like image 694
chris Frisina Avatar asked Nov 30 '22 14:11

chris Frisina


2 Answers

You can use not logical operator, Try this:

if (!$(this).hasClass('white')) {console.log('not white');};

Returns false if its single operand can be converted to true; otherwise, returns true.

like image 135
undefined Avatar answered Dec 10 '22 19:12

undefined


I think it might be helpful for you to understand the domains you're crossing in those two statements.

if ($('this:not(.white)')) {console.log('not white');};

This statement will not work, because the selector - this:not(.white) will look for elements of this variety: <this class="white"></this>. Your selector, in other words, is looking for an HTML element of type this, which is not of class white.

if ($(this).not('.white')) {console.log('not white');};

In this case, you are using $(this), which wraps the JavaScript object which the this keyword refers to in a jQuery object, thus allowing you to utilize jQuery methods against that DOM element.

In order to get the effect that you're looking for, you have to understand that any STRING selector you pass to a $(selector) is constrained to selectors which CSS can match. Thus - you can't use your "this" keyword that way.

What you can do, to check your effect, however, is the following:

if ($(this).is(':not(.white)')) {
    console.log('Not White! :(');
} else {
    console.log('White! :D');
}

Because you put this inside the $() block, the result is that any further jQuery chained methods which are applied are resolved against the DOM element to which this refers in your current context. You are then checking the class using the CSS :not() selector.

Please note, however, that the limitation of this approach is that if for whatever reason this refers to multiple DOM elements, the .is() result will only return true if ALL such elements match the selector. So - consider this example:

<div class="one white element"></div>
<div class="one black element"></div>
<div class="one green element"></div>

$('.one.element').bind('click', function () {
    // In this context, 'this' refers to the element which was clicked.
    console.log( $(this).is(':not(.white)') );

    // If you click either the black or green element, you will get a 'true',
    // because those elements are not .white.
    // If you click the white element, you will get a 'false',
    // because that element does have the .white class
});

The problem is that the context for this changes fairly often in most JavaScript applications, and therefore most programmers I know avoid using it whenever possible. Safer than the above is:

$('.one.element').bind('click', function (ev) {
    var $el = $(ev.target);
    console.log( $el.is(':not(.white)') );

    // In this case, you avoid 'this' entirely, and target the actual element
    // from which the event originated.
});

In this case, however, you run into the problem of nested items raising incorrect targets. Consider this case:

<div class="parent">
    <div class="child">
        text
    </div>
</div>

$('.parent').bind('click', function (ev) {
    var $el = $(ev.target);
    console.log( $el.attr('class') );
});

In this case, if you click the parent itself, you will get parent as the result. If you click the child, however, even though the event is bound to the parent element, you will get child because of event bubbling. The actual event was raised by the child element, and therefore you have mis-targeted.

So - usually when you are building plugins, it is wise to carefully control your references.

Example

<div class="parent">
    <div class="child">
        text
    </div>
</div>

var $parent = $('.parent').bind('click', function () {
    console.log( $parent.attr('class') );
});

Now it doesn't matter whether you click the parent or child, you get the correct result, and you know what you're referencing. No confusion of this contextual changes and no chance of using the attributes of a subordinate node.

Incidentally - any of the methods posted in other answers here are valid, also.

// The following will all tell you if the node HAS the class:
$(selector).hasClass('white')
$(selector).is('.white')
$(selector).is('[class*=white]')

// The following will all tell you if the node DOES NOT have the class:
!$(selector).hasClass('white')
$(selector).not('.white')
$(selector).is(':not(.white)')

And - there are other ways to do it, but any of these should work for your purposes. :)

like image 37
Troy Alford Avatar answered Dec 10 '22 20:12

Troy Alford