Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

286
Visualizações
JavaScript Custom Star Rating System

I want to create a star rating system that has 5 stars. You can not select a half star, only a whole one. I want to achieve the following: If the user clicks on the star, the cilcked one and the other before it should be activated, and if the user clicks on a lower star deactivate all the stars after the selected one.

Here is what I got so far: The user can select 4 stars out of five (on the fifth click I have a bug which should be solved).

PS: I am working with SVG images but it would be way too ugly to insert in so the [ ] are the empty stars (the default), and the [X] are the selected (active) stars.

Heres my code:

for (let i = 1; i <= 5; i++) { document.getElementById("w__stars").innerHTML += `<span class="r__icon">[ ]</span>`; }
var icon = document.getElementsByClassName("r__icon");
for (let i = 0; i < icon.length; i++) {
  icon[i].addEventListener("click", function (e) { console.log("--");
    for (let j = 0; j < i+1; j++) {
    console.log("i: " +i); console.log("j: "+(j+1)); console.log("Rest: "+ (j+(5-(i+1))));
      icon[j].innerHTML = `[X]`;
      icon[i+(5-(i+1))].innerHTML = `[ ]`;
    }
  });
}
<div class="flex flex-row product-star-con" id="w__stars"></div>

about 4 years ago · Juan Pablo Isaza
2 Respostas
Responde à pergunta

0

Your method just needs a different approach. For instance that inner loop is unnecessary if you are to place this in there icon[j].innerHTML = '[X]'.. which can be placed just within the outer loop.

Also the unnecessary calculations are making the task seem harder than it actually is. And since this is a loop, the i variable will always have the highest value within the loop, since there is no break statement in there

The method below targets the next elements and previous elements relative to the one being clicked at the moment and applies the appropriate 'innerHTML' to them

// Function to get previous and next siblings of the target element
function getSiblings(element,  type){
    var arraySib = [];
    if ( type == 'prev' ){
        while ( element = element.previousSibling ){
            arraySib.push(element);
        }
    } else if ( type == 'next' ) {
        while ( element = element.nextSibling ){
            arraySib.push(element);
        }
    }
    return arraySib;
}
for (var i = 1; i <= 5; i++) { document.getElementById("w__stars").innerHTML += `<span class="r__icon">[ ]</span>`; }
var icon = document.getElementsByClassName("r__icon");
for (var i = 0; i < icon.length; i++) {
  icon[i].addEventListener("click", function (e){
    this.innerHTML = `[X]`;
    var prev = getSiblings(this, 'prev')
    var next = getSiblings(this, 'next')
    // populate previous siblings
    for(p = 0; p < prev.length; p++){
       prev[p].innerHTML = `[X]`
    }
    // clear next siblings
    for(n = 0; n < next.length; n++){
       next[n].innerHTML = `[]`
    }
  });
}
<div class="flex flex-row product-star-con" id="w__stars"></div>

about 4 years ago · Juan Pablo Isaza Relatório

0

Another approach:

// Setting stars
const stars = [];
for (let i = 0; i <= 4; i++) {
    stars.push({
    active: false,
    index: i
  });
}

const renderStars = (parentElement, stars, activeContent, notActiveContent) => {
    parentElement.innerHTML = '';
    stars.forEach(({ active, index }) => {
    parentElement.innerHTML += `
        <span class="r__icon">${active ? activeContent : notActiveContent}</span>`;
  });
  
  Array.from(parentElement.querySelectorAll('.r__icon')).forEach((item, itemIndex) => {
    const star = stars.find(({ index }) => index === itemIndex);
    stars[star.index].element = item;
  
    item.addEventListener('click', (e) => {
        const itemElement = e.target;
      const starIndex = stars.findIndex(({ element }) => element === itemElement);
      if (starIndex === -1) {
        return;
      }
      
      const toActive = stars[starIndex].active !== true;
      stars = stars.map(star => {
        if (toActive) {
            // Set items before index to true, and after to false
            if (star.index <= starIndex) {
            return {
                ...star,
              active: true
            };
          }
          
          return {
            ...star,
            active: false
          };
        } else {
            // Set items after index to false, and before to true
          if (star.index >= starIndex) {
            return {
              ...star,
              active: false
            };
          }
          
          return {
            ...star,
            active: true
          };
        }
      });
      
      renderStars(parentElement, stars, activeContent, notActiveContent);
    });
  });
};

const setupStars = (stars, activeContent, notActiveContent) => {
    const parentElement = document.getElementById("w__stars");
  if (!parentElement) {
    return;
  }
  
  renderStars(parentElement, stars, activeContent, notActiveContent);
};

setupStars(stars, '[X]', '[ ]');
<div class="flex flex-row product-star-con" id="w__stars"></div>

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda