76

I have a simple add attribute function:

$(".list-toggle").click(function() {
    $(".list-sort").attr('colspan', 6);
});

My question is: how can I turn this into a toggle, so colspan="6" is removed from the element on the next click?

Joe
  • 15,205
  • 8
  • 49
  • 56
alias51
  • 8,178
  • 22
  • 94
  • 166
  • 2
    Have you tried pure JS? There is this method `.toggleAttribute()` https://developer.mozilla.org/en-US/docs/Web/API/Element/toggleAttribute – Daut Dec 17 '18 at 14:02

8 Answers8

187

If you're feeling fancy:

$('.list-sort').attr('colspan', function(index, attr){
    return attr == 6 ? null : 6;
});

Working Fiddle

ES6 Syntax (2021):

$('.list-sort').attr('colspan', (_, attr) => attr == 6 ? null : 6));
Stef Heyenrath
  • 9,335
  • 12
  • 66
  • 121
RienNeVaPlu͢s
  • 7,442
  • 6
  • 43
  • 77
  • Super elegant, can you explain the logic behind this? – Gcamara14 Jan 25 '20 at 01:35
  • 2
    @Gcamara14 `$('.list-sort')` targets the element in the DOM `.attr()` is a jQuery function to set the attribute value which takes two arguments `attribute` and `value`. `'colspan`' is the attribute argument in this case and the value is the anonymous function. `function(index, attr){ return attr == 6 ? null : 6; }` This function uses a ternary operator `?` which is similar to an `if statement`. If the `attr` passed equals `6` return `null` else return `6` – tralawar May 22 '20 at 17:57
64
$('.list-toggle').click(function() {
    var $listSort = $('.list-sort');
    if ($listSort.attr('colspan')) {
        $listSort.removeAttr('colspan');
    } else {
        $listSort.attr('colspan', 6);
    }
});

Here's a working fiddle example.

See the answer by @RienNeVaPlus below for a more elegant solution.

musicnothing
  • 3,977
  • 24
  • 43
41

For readonly/disabled and other attributes with true/false values

$(':submit').attr('disabled', function(_, attr){ return !attr});
BitOfUniverse
  • 5,903
  • 1
  • 34
  • 38
  • 7
    for me, the attr was `typeof string`, so i wrote `$(selector).attr('aria-expanded', function(_, attr) { return !(attr == 'true') })` – honk31 Jul 06 '17 at 11:17
  • This is a nice answer, since it trigger the change of attribute only once. Is using it for a toggle switch with 3 possible values ("", "N" and "Y") – Plasebo May 28 '20 at 09:01
11

I know this is old and answered but I recently had to implement this and decided to make 2 simple jQuery plugins that might help for those interested

usage:

// 1
$('.container').toggleAttr('aria-hidden', "true");
// 2
$('.container').toggleAttrVal('aria-hidden', "true", "false");

1 - Toggles the entire attribute regardless if the original value doesn't match the one you provided.

2 - Toggles the value of the attribute between the 2 provided values.

 // jquery toggle whole attribute
  $.fn.toggleAttr = function(attr, val) {
    var test = $(this).attr(attr);
    if ( test ) { 
      // if attrib exists with ANY value, still remove it
      $(this).removeAttr(attr);
    } else {
      $(this).attr(attr, val);
    }
    return this;
  };

  // jquery toggle just the attribute value
  $.fn.toggleAttrVal = function(attr, val1, val2) {
    var test = $(this).attr(attr);
    if ( test === val1) {
      $(this).attr(attr, val2);
      return this;
    }
    if ( test === val2) {
      $(this).attr(attr, val1);
      return this;
    }
    // default to val1 if neither
    $(this).attr(attr, val1);
    return this;
  };

This is how you would use it in the original example:

$(".list-toggle").click(function() {
    $(".list-sort").toggleAttr('colspan', 6);
});
Francisc0
  • 968
  • 1
  • 14
  • 28
5

This would be a good place to use a closure:

(function() {
  var toggled = false;
  $(".list-toggle").click(function() {
    toggled = !toggled;
    $(".list-sort").attr("colspan", toggled ? 6 : null);
  });
})();

The toggled variable will only exist inside of the scope defined, and can be used to store the state of the toggle from one click event to the next.

Community
  • 1
  • 1
thirdender
  • 3,891
  • 2
  • 30
  • 33
  • What if it gets changed from somewhere else? – nafg Oct 22 '15 at 02:07
  • I don't know if I follow. Any click on an element with the class `list-toggle` will trigger the function, which changes the boolean variable `toggled`. The attribute is then either set or unset depending on the state of the variable `toggled`. – thirdender Oct 23 '15 at 05:16
  • 1
    @thirdender your code breaks if something other than a click event modifies the state of the attribute. – Hybrid web dev Mar 08 '17 at 02:05
  • 2
    Upvoted because this is a very good example of the meaning of a closure – Brice Coustillas Aug 21 '17 at 14:25
3
$(".list-toggle").click(function() {
    $(this).hasAttr('colspan')
        ? $(this).removeAttr('colspan')
        : $(this).attr('colspan', 6);
});
James
  • 4,644
  • 5
  • 37
  • 48
Zuks
  • 1,247
  • 13
  • 20
2
$(".list-toggle").click(function() {
    $(this).attr('colspan')
        ? $(this).removeAttr('colspan')
        : $(this).attr('colspan', 6);
});
James
  • 4,644
  • 5
  • 37
  • 48
user2398069
  • 385
  • 1
  • 5
  • 13
0

This answer is counting that the second parameter is useless when calling removeAttr! (as it was when this answer was posted) Do not use this otherwise!

Can't beat RienNeVaPlus's clean answer, but it does the job as well, it's basically a more compressed way to do the ternary operation:

$('.list-sort')[$('.list-sort').hasAttr('colspan') ? 
    'removeAttr' : 'attr']('colspan', 6);

an extra variable can be used in these cases, when you need to use the reference more than once:

var $listSort = $('.list-sort'); 
$listSort[$listSort.hasAttr('colspan') ? 'removeAttr' : 'attr']('colspan', 6);
Daniel
  • 46
  • 1
  • 3