How can I target only visible objects with nth-child?


Tags: jquery,css,css-selectors

Problem :

I have 5 items, and a button above them to inform how many items will be displayed. For each item I have a different background image.

The problem is that when a person hits an item, that item will be removed and another item will be appended with jQuery and when a new item is appended, it goes to the end of the line, making it the 5th element and then making it with the background of the 5th item but there are times that the 5th item is the only visible and it should be with the background of the 1st item.

Here is a JSFiddle: https://jsfiddle.net/wmerussi/csqge7jr/

In the beginning you have 5 items, note that the 5th item is blue, now if you choose to display only 1 item, and click that item to remove it, the other item will be blue (the color of 5th item).

Is it possible to have only the visible items targeted? Or is it possible to re-arrange the visible <li>s to the beginning of the list?

HTML:

<div class="one">1</div>
<div class="two">2</div>
<div class="three">3</div>
<div class="four">4</div>
<div class="five">5</div>

<ul>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
</ul>

jQuery:

$('div').on('click', function() {
    var num = $(this).text();
    for(var i=0; i<5 ;i++) {
        if(i < num) {
            $('li').eq(i).fadeIn();
        } else {
            $('li').eq(i).fadeOut();
        }
    }
});

$(document).on('click', 'li', function() {
    $(this).fadeOut(function() {$(this).remove();});
    $(this).parent().append('<li></li>');
});

CSS:

div {
    display: inline-block;
    margin-right: 10px;
    width: 30px;
    height: 30px;
}

li:nth-child(1), .one {
    background-color: green;
}


li:nth-child(2), .two{
    background-color: orange;
}

li:nth-child(3), .three{
    background-color: red;
}

li:nth-child(4), .four{
    background-color: pink;
}

li:nth-child(5), .five{
    background-color: blue;
}

update
How to reproduce the issue
click on my JSFiddle and then chose to show only 1 item (the green "1" box at top). After that if you click that visible item to remove it (with jQuery), you will see that the appended items will be blue, because they are being appended to the end of the ul list, making it the 5th element. But it is the first visible item, so it should be green.



Solution :

My solution would be to create a function that manages adding removing classes to items based on their position and visibility, and call that function after each event that updates the items in some way.
This way you can keep the items classes management separate from the code that updates the items

$(function() {

  //the class management function
  function updateElemClasses() {
    //all color based classes the lists can have
    var classes = ['one', 'two', 'three', 'four', 'five'];

    //wait for fadeout to happen. Fadeout could take longer but this is just a proof of concept
    window.setTimeout(function() {
      $('li:visible').each(function(idx) {
        $(this).removeClass(classes.join(' ')).addClass(classes[idx]);
      })
    }, 500);

  }

  $('div').on('click', function() {
    var num = $(this).text();
    for (var i = 0; i < 5; i++) {
      if (i < num) {
        $('li').eq(i).fadeIn();
      } else {
        $('li').eq(i).fadeOut();
      }
    }
    updateElemClasses()
  });

  $(document).on('click', 'li', function() {
    $(this).fadeOut(function() {
      $(this).remove();
    });
    $(this).parent().append('<li>' + $(this).text() + '</li>');

    updateElemClasses()
  });

  updateElemClasses();
});
/* you do not need nth-child now */

div {
  display: inline-block;
  margin-right: 10px;
  width: 30px;
  height: 30px;
}
.one {
  background-color: green;
}
.two {
  background-color: orange;
}
.three {
  background-color: red;
}
.four {
  background-color: pink;
}
.five {
  background-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div class="one">1</div>
<div class="two">2</div>
<div class="three">3</div>
<div class="four">4</div>
<div class="five">5</div>

<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
</ul>


    CSS Howto..

    How can clients without Ruby view web pages using SASS?

    How to center text in lists?

    How to create a css hoverover box with two section

    CSS: How to make this kind layout?

    How to create zebra-stripe CSS with TAL?

    CSS Position Help (horizontal sidebar showing up when animate content over)

    How to parse a specific link using a Selector CSS Query

    How to enable real time CSS editing in chrome?

    How to make font size independent of screen resolution and monitor size?

    How to Center a image with HTML CSS

    Hide and show when click a button

    How to rotate an image with CSS style transform by an variable of degree?

    How do I create a menu that appears on hover?

    How to stop image shrinking when page is resized horizontally in CSS

    How to enable top and bottom margins between a series of spans inside a div?

    How to center a child element in CSS, even if it is larger than the parent?

    How to fit HTML table row to its content

    How to apply css for anchor tag inside table

    How to style all the same XSL FO elements? XSL FO like CSS?

    CSS div element - how to show horizontal scroll bars only?

    How to make Visual Studio stop “compiling” .js and .css files

    How to integrate site and iframe scroll bar?

    how to make slide animation?

    How to stop CSS within a RichText field from overwriting document

    jQueryUI show/hide animation issue with child nodes

    How to auto adjust (stretch) div height and width using jQuery or CSS

    How to switch css table-cell from left to right?

    How to fully stretch 2 embeded divs?

    How to hide overflow characters of a div when resizing [duplicate]

    How to handle caching of GWT theme CSS files