Search code examples
javascriptmodernizrobject-literal

Javascript shorthand ternary operator not working when setting to variable in object literal


I am trying to cache variables when JS first runs, and I need to check for classes on html element either .supports-no-touch or .no-touch (to make sure to catch either versions depending on which version Modernizr is used).

When I run it like this,

window.MyScript = window.MyScript || {};
MyScript.cacheSelectors = function () {
  MyScript.cache = {
    $slideoutNavDesktop: ($('.supports-no-touch #slideoutNav') || $('.no-touch #slideoutNav'))
    // OR
    // $slideoutNavDesktop: $('.supports-no-touch #slideoutNav') ? $('.supports-no-touch #slideoutNav') : $('.no-touch #slideoutNav')
  }
};
MyScript.cacheSelectors();
console.log( MyScript.cache.$slideoutNavDesktop );

The result of the console.log is undefined empty jQuery object, like:

► [prevObject: n.fn.init(1), context: document, selector: ".supports-no-touch #slideoutNav"]

When I run the same code in console, like

console.log( $('.supports-no-touch #slideoutNav') || $('.no-touch #slideoutNav') );
console.log( $('.supports-no-touch #slideoutNav') ? $('.supports-no-touch #slideoutNav') : $('.no-touch #slideoutNav') );

I get the right element.

Also, I know that on page load, the html element does have the .no-touch class.

What am I doing wrong?

EDIT: I was getting undefined due to a spelling error in the variable reference.


Solution

  • jQuery always returns a non-null object reference, which is always truthy, so neither of those will work. I think the results you're seeing in the console are the result of some kind of confusion (the console can be a bit confusing).

    You can use the conditional operator, but you need to check .length:

    var x = $('.supports-no-touch #slideoutNav').length ? $('.supports-no-touch #slideoutNav') : $('.no-touch #slideoutNav');
    

    ...but that does the DOM query twice. So instead:

    var x = $('.supports-no-touch #slideoutNav');
    if (!x.length) {
        x = $('.no-touch #slideoutNav');
    }
    

    But, the simpler answer is to use a selector group and take the first (possibly only) result:

    var x = $('.supports-no-touch #slideoutNav, .no-touch #slideoutNav').first();
    

    Note: Your query suggests that you have the same ID on more than one element. That's invalid. ID values must be unique. So if you're going to use the above, I suggest changing the #slideoutNav to .slideout-nav or similar, and changing id="slideoutNav" on the elements involved to class="slideout-nav" (adding slideout-nav to their existing class attribute if they have one).