somejkuser
somejkuser

Reputation: 9040

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>

Upvotes: 0

Views: 108

Answers (2)

Santi
Santi

Reputation: 679

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>

Upvotes: 1

Kosh
Kosh

Reputation: 18378

There is a simpler pure CSS solution:

.rating-selector {
  display: inline-block;
  border: 0;
  direction: rtl;
}

input[name="rating"] {
  display: none;
}

input[name="rating"]~label {
  color: grey
}

input[name="rating"]:checked~label {
  color: gold
}
<fieldset class="rating-selector">
  <input type="radio" name="rating" value="5" id="rating-5" />
  <label for="rating-5">★</label>
  <input type="radio" name="rating" value="4" id="rating-4" />
  <label for="rating-4">★</label>
  <input type="radio" name="rating" value="3" id="rating-3" />
  <label for="rating-3">★</label>
  <input type="radio" name="rating" value="2" id="rating-2" />
  <label for="rating-2">★</label>
  <input type="radio" name="rating" value="1" id="rating-1" />
  <label for="rating-1">★</label>
</fieldset>

Upvotes: 0

Related Questions