B.B
B.B

Reputation: 164

JQuery Toggle icon with a variety of different icons issue

I am currently trying to set up a menu with a icon toggle, so when one icon is clicked it changes to a cross and then when that cross is clicked it changes back to the original. I have got that far, but when I click a new image I want the old icon to reset and the cross to be applied to the new icon.

This is how far I have got:

<div class="panel panel-default">
    <div class="panel-heading" role="tab" id="headingFive">
        <a class="collapsed faq-links">
            <i id="icon" class="fa fa-info-circle fa-3x"></i>
        </a>
    </div>
</div>
<br />
<div class="panel panel-default">
    <div class="panel-heading" role="tab" id="heading13">
        <a class="collapsed faq-links">
            <i id="icon" class="fa fa-heartbeat fa-3x"></i>
        </a>
    </div>       
</div>
<br />
<div class="panel panel-default">
    <div class="panel-heading" role="tab" id="headingFour">
        <a class="collapsed faq-links" >
            <i id="icon" class="fa fa-comments fa-3x"></i>
        </a>
    </div>
</div>

Javascript:

$('.faq-links').click(function(){
    var collapsed=$(this).find('i').hasClass('fa-info-circle');
    $('.faq-links').find('i').removeClass('fa-times');
    $('.faq-links').find('i').addClass('fa-info-circle');
    if(collapsed)
        $(this).find('i').toggleClass('fa-info-circle fa-3x fa-times fa-3x')
});

I've set up a JSFiddle to show it working https://jsfiddle.net/BenjiBaird/yycf2jb8/1/

So when I click on info-circle the cross is applied and when I click on another that cross is removed. How do I go about applying this so every icon.

Any help would be appreciated, hope I made myself clear.

Upvotes: 4

Views: 1387

Answers (4)

Kacper Knapik
Kacper Knapik

Reputation: 323

HTML:

<i id="icon" class="fa fa-heartbeat fa-3x" data-icon="fa-heartbeat"></i>

About HTML:

For storing the icon name, the best way would be using data-attributes. It is easy to understand + you will have no problem with changing it in the future. Make sure, you use id attribute only for one DOM Element, for multiple elements, use class attribute.

JS:

// jQuery safety
(function($) {

  // DOM ready
  $(function() {

    // icons
    var $icons = $('.faq-links');
    $icons.on('click', function(e) {

      // variables
      var $this = $(this);
      var $icon = $this.find('i');

      // iconName taken from data-icon attribute
      var iconName = $icon.data('icon');

      // close icon
      var closeIconName = 'fa-times';

      // prevent default browser behaviour, just in case
      e.preventDefault();

      // handle state
      if ($icon.hasClass(closeIconName)) {
        $icon.removeClass(closeIconName).addClass(iconName);
      } else {
        $icon.addClass(closeIconName).removeClass(iconName);
      };
    });
  });
})(jQuery);

About JS:

I believe in clean code writing. The cleaner, the better - stick with that in your coding adventure. First, we take $icons - every icon we have. We are waiting for click event. Once one of the $icons is clicked, we set $this as the clicked icon. We also set $icon as <i></i> element inside clicked icon, just for cleaner code.

iconName is equal to icon's data-attribute, so we can use it easily in further steps.

Now we have // handle state section. It is simple to understand, that if the $icon has class, which is equal to closeIconName (cross in this example), it is 'active'. So once this 'active' icon is clicked, we remove 'active' state, which means, we remove closeIconName class and we add iconName which is the default icon name (took from data-attribute). If the icon isn't 'active', we remove the icon and we add closeIconName icon.

NOTE: icon without data-attribute simply doesn't change to fa-close icon.

EDIT: here is JSFiddle: https://jsfiddle.net/0fy2po3b/1/

Upvotes: 0

Olivier HUET
Olivier HUET

Reputation: 1

If you have a way to ensure that the class fa-times takes precedence over the fa-heartbeat, fa-info-circle and fa-comments classes this simple code would work just fine.

$('.faq-links').click(function() {
  var blockI = $(this).find('i');
  if(blockI.hasClass('fa-times')) {
    // remove fa-times class if the element already has it
    blockI.removeClass('fa-times');
  }
  else {
    // clean the classes from other elements that might have it
    $('.faq-links i').removeClass('fa-times');
    // adds it on the clicked element
    blockI.addClass('fa-times');
  }
});

You can redefine class fa-times in a later css file or style block and/or using a more specific selector to redefine the class so that fa-times style "overrides" the other classes. That would be the best for me because you dont need to mess around with the other classes. You can modify the order of the links or add news ones and the script would still work.

Upvotes: 0

Theodore K.
Theodore K.

Reputation: 5176

I would remove the "cross" icon classes from all buttons, then reset all buttons to their default icon and finally draw the "cross" (if needed) for the current one. Like this:

$('.faq-links').click(function(){
        var notCollapsed = $(this).find('i').hasClass('fa-times');              

        //Remove crosses from all buttons
        $('.faq-links').find('i').removeClass('fa-times');          

        //Reset the default icon for each button 
        $('.faq-links:eq(0)').find('i').addClass('fa-info-circle');
        $('.faq-links:eq(1)').find('i').addClass('fa-heartbeat');
        $('.faq-links:eq(2)').find('i').addClass('fa-comments');

        //Draw the cross if needed
        if(!notCollapsed) $(this).find('i').attr("class",'fa fa-times fa-3x');
});

See your update fiddle https://jsfiddle.net/8odoros/yycf2jb8/10/

Upvotes: 1

Mark Walters
Mark Walters

Reputation: 12400

If you add a data attribute to the anchor tags with the specific icon class name like so

<a class="collapsed faq-links" data-icon-name="fa-info-circle">
  <i id="icon" class="fa fa-info-circle fa-3x"></i>
</a>

You can use that attribute to toggle the icons between the 'fa-times' and the original one

Have a look at the code below and the JSFiddle to see how it works. Also there are inefficiencies in the code namely in the constantly using .find('i') but i'll leave it up to you to come up with a solution for that.

$('.faq-links').click(function() {
  if ($(this).find('i').hasClass('fa-times')) { //then change back to the original one
    $(this).find('i').removeClass('fa-times').addClass($(this).data('icon-name'));
  } else {
    $('.faq-links').each(function(){ //Remove the cross from all other icons
        if($(this).find('i').hasClass('fa-times')) {
        $(this).find('i').removeClass('fa-times').addClass($(this).data('icon-name'));
      }
    });
    $(this).find('i').addClass('fa-times').removeClass($(this).data('icon-name'));
  }
}); 

The Fiddle is here

Upvotes: 4

Related Questions