javascriptjqueryhtmldom-traversal

Simple dom traversal using jquery


I am working with a prior developers star rating code. I need to modify it because it doesn't operate the way the developer intended. If you look, there are label elements with stars inside. You can see the first label has 1 span, while the 5th label has 5 spans.

An example of how it's working now is you click on the 5th input the developer has 5 stars inside the label, but to get it to work as intended I actually need to modify the other label spans as well. So, let's say the user chooses 3 stars, I'd need to mutate the span inside labels 1, 2, and 3. For choosing 4 stars, I'd need to mutate the span inside labels 1, 2, 3, and 4.

I was thinking about a jquery/javascript solution that traverses labels (maybe with ids). So if they click on input 4, the javascript solution would loop through all spans inside labels 1, 2, 3, and 4 and update the css. I'm not sure how to do this though.

<div class="rating-selector">
    <label>
        <input type="radio" name="rating" value="1" />
        <span class="icon">★</span>
    </label>
    <label>
        <input type="radio" name="rating" value="2" />
        <span class="icon">★</span>
        <span class="icon">★</span>
    </label>
    <label>
        <input type="radio" name="rating" value="3" />
        <span class="icon">★</span>
        <span class="icon">★</span>
        <span class="icon">★</span>   
    </label>
    <label>
        <input type="radio" name="rating" value="4" />
        <span class="icon">★</span>
        <span class="icon">★</span>
        <span class="icon">★</span>
        <span class="icon">★</span>
    </label>
    <label>
        <input type="radio" name="rating" value="5" />
        <span class="icon">★</span>
        <span class="icon">★</span>
        <span class="icon">★</span>
        <span class="icon">★</span>
        <span class="icon">★</span>
    </label>
</div>

Solution

  • You could find the parent <label> index by using .closest("label").index(). Then, use the :lt() selector to grab each item before it.

    const highlightPrevious = (elem) => {
      let $this = $(elem);
      $(".rating-selector label span").css("color", "");                 //reset styling
      let idx = $this.index();                                           //get index of selected label
      $(`.rating-selector label:lt(${idx+1}) span`).css("color", "red"); //style all label spans up to and including the selected index
    };
    
    $('label')
      .click(function() { highlightPrevious(this); })
      .mouseover(function() { $(this).click() });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <div class="rating-selector">
      <label>
        <input type="radio" name="rating" value="1" />
        <span class="icon">★</span>
      </label>
      <label>
        <input type="radio" name="rating" value="2" />
        <span class="icon">★</span>
        <span class="icon">★</span>
      </label>
      <label>
        <input type="radio" name="rating" value="3" />
        <span class="icon">★</span>
        <span class="icon">★</span>
        <span class="icon">★</span>   
      </label>
      <label>
        <input type="radio" name="rating" value="4" />
        <span class="icon">★</span>
        <span class="icon">★</span>
        <span class="icon">★</span>
        <span class="icon">★</span>
      </label>
      <label>
        <input type="radio" name="rating" value="5" />
        <span class="icon">★</span>
        <span class="icon">★</span>
        <span class="icon">★</span>
        <span class="icon">★</span>
        <span class="icon">★</span>
      </label>
    </div>