Michael Itzoe
Michael Itzoe

Reputation: 1959

Deselecting an element in jQuery

I have a collection of span elements. In the code I have a global variable that represents the "selected" object. Using the click event when a span is clicked I reset the object's class, reset the global variable, then set the object to the variable and change its class (to make it "highlighted"). This effectively toggles selection when clicking an object.

var currentItem = null;
$( ".item" ).click( function() {
    if( $( this ).hasClass( "selected" ) ) {
        $( this ).removeClass( "selected" )
        currentItem = null;
    } else {
        if( $( ".item" ).hasClass( "selected" ) ){
            $( ".item" ).removeClass( "selected" )
        }

            $( this ).addClass( "selected" );
            currentItem = $( this );
        }
} );

What I'd like to be able to do is unselect when clicking on an empty area of the page. I tried creating a click event on the body object, but that overrode the span click event so nothing was selected. I'm a complete jQuery noob and not sure where to go with this.

Upvotes: 1

Views: 4912

Answers (7)

sbmaxx
sbmaxx

Reputation: 886

Too much code, we can do it easier:


"use strict";
/*global $*/
$(function () {
  $('html').live('click', function (e) {
    $('.item.selected').removeClass('selected');

    var $t = $(e.target);
    if ($t.hasClass('item')) {
      $t.addClass('selected');
    }
  });
});

Using 'html' to bind event is better due body can be not 100% height, for example. And clicking on empty area return not expected result.

We do not need global object, as this script guarantees that we have only one selected span and we can refer to it with:


$('.item.selected'); 

Upvotes: 0

user113716
user113716

Reputation: 322492

Your idea to place the click event on the body is fine.

You just need to be aware that clicking on any descendants of body will cause the click event to bubble up to body, and fire that handler.

You need to stop that propagation in your span event handler.

$( ".item" ).click( function(event) {
    event.stopPropagation();
    ...

jQuery Docs

event.stopPropagation() http://api.jquery.com/event.stopPropagation/


EDIT:

Another valid alternative would be to simply return false at the end of the handler.

$( ".item" ).click( function() {
    // Your code...
    return false;
});

Upvotes: 2

Nick Craver
Nick Craver

Reputation: 630409

Use event.stopPropagation() in your current handler so that click doesn't bubble up to the <body>, triggering it's handler as well, then your approach works, like this:

var currentItem = null;
$(".item").click(function(e) {
  if($(this).hasClass("selected")) {
    $(this).removeClass("selected")
    currentItem = null;
  } else {
    $(".item.selected").removeClass("selected");
    currentItem = $(this).addClass("selected");
  }
  e.stopPropagation();
});
$(document).click(function() {
  $(".item.selected").removeClass("selected");
});

You can view a demo here, one suggestion though, if only one element can be selected do you need to keep track of it? If lookup cost isn't a factor, you could aways find the currentItem by doing $(".item.selected"), simplifying this code quite a bit. I'm not sure how you're using currentItem, just an option you have :)

Upvotes: 7

Tomalak
Tomalak

Reputation: 338208

You don't necessarily need a global variable since your DOM holds that state info, too.

// de-select old selection and select new item
$(".item").click( function(evt) {
  $(".item.selected").removeClass("selected");
  $(this).addClass("selected");
  evt.stopPropagation();
});

// de-select everything
$("body").click( function() {
  $(".item.selected").removeClass("selected");
});

// your currently selected element can be retrieved by this anytime:
$(".item.selected")[0]

Not tracking state twice (in the DOM and in a global variable) spares you two headaches:

  • carefully updating the global variable all the time
  • bugs that arise of "global" state getting out of sync with "DOM" state

Upvotes: 1

Brian Lacy
Brian Lacy

Reputation: 19098

In addition to the answers stated (unless I missed this), you needn't attach the click() event to the body when the page loads -- you can simply do it after the item is selected. Not that it hurts since you're stopping propagation, but in my view its more "correct" to only activate/set an event handler for the duration in which it is relevant.

Upvotes: 0

lewiguez
lewiguez

Reputation: 3823

Create a click on the html element $("html") and return it as false whenever you do what you need to do. The body could not extend the whole page if you're doing some sizing with CSS with it. Here's an example:

$("html").click( function(e) {

    e.stopPropagation()

});

Edit

Yeah. forgot about stopPropagation(). Changed code to read that. Should still use the html element as the listener, however.

Upvotes: 0

Gabriele Petrioli
Gabriele Petrioli

Reputation: 195992

You did well setting a click event on the body. BUt you must also tell the span click event to stop the propagation of the event..

$( ".item" ).click( function(event) {

    event.stopPropagation();
    //your code
});

Upvotes: 5

Related Questions