-4

I am a student and learner, I am making a star rating function using jQuery. Here is my code: HTML Code:

for (var i = 1; i < 6; i++) {
  console.log(i);
  var cls = ".star_".concat(i);
  var sp_cls = ".star_color_".concat(i);
  console.log(cls);
  $(cls).click(function() {
    $(sp_cls).toggleClass(sp_cls);
    $("#rate").html("<b>Hello world!</b>");
    console.log(i);
  });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
<!-- Rating Stars Box -->
<div class='rating-stars text-center p-2 mt-3'>
  <h5 id="rate">Rate this answer here!</h5>
  <ul id='stars'>
    <li class='star_1' title='Poor' data-value='1'>
      <span class='star_color_1'>
                <i class='fa fa-star fa-fw fa-2x'></i>
            </span>
    </li>
    <li class='star_2' title='Fair' data-value='2'>
      <span class='star_color_2'>
                <i class='fa fa-star fa-fw fa-2x'></i>
            </span>
    </li>
    <li class='star_3' title='Good' data-value='3'>
      <span class='star_color_3'>
                <i class='fa fa-star fa-fw fa-2x'></i>
            </span>
    </li>
    <li class='star_4' title='Excellent' data-value='4'>
      <span class='star_color_4'>
                <i class='fa fa-star fa-fw fa-2x'></i>
            </span>
    </li>
    <li class='star_5' title='WOW!!!' data-value='5'>
      <span class='star_color_5'>
                <i class='fa fa-star fa-fw fa-2x'></i>
            </span>
    </li>
  </ul>
</div>

In this I am passing variable named "cls" instead of class name, it is not showing any error in console but my program is not working. Why so?

Karan
  • 12,059
  • 3
  • 24
  • 40
Mrunmai Dahare
  • 128
  • 1
  • 8
  • 1
    We need your HTML as well to help you. Can you add that too, please? Also, what does this do? `"star_color_".concat(i);` instead, you could have used `"star_color_" + i`. Create a [mcve]. Also, use a DOM Selector with either `.` or `#` prepended. – Praveen Kumar Purushothaman Aug 10 '20 at 12:52
  • 1
    Also you should be using `let i = 1` instead of `var i = 1`. Refer this issue https://stackoverflow.com/questions/42757887/javascript-closure-event-handler-issue# – Karan Aug 10 '20 at 13:24

3 Answers3

1

You code looks very similar to this snippet here:

https://codepen.io/mmoradi08/pen/yLyYrGg

I took the liberty of converting that code into a jQuery plugin and cleaned it up a bit. I am not sure you would need to modify it any further.

You can call the plugin, as seen below, by invoking the function on the jQuery object. It takes an optional config with a callback function.

$('.rating-stars').ratingWidget({
  callback: responseMessage
});

/* jquery.rating-widget.js */
($ => {
  const defaultConfig = { callback: null  };
  $.fn.ratingWidget = function(config) {
    const opts = { ...defaultConfig, ...config };
    this.find('ul li').on({
      mouseover: function() {
        const currRating = parseInt($(this).data('value'), 10);
        $(this).parent().children('li.star').each(function(index) {
          $(this).toggleClass('hover', index < currRating);
        });
      },
      mouseout: function() {
        $(this).parent().children('li.star').removeClass('hover');
      },
      click: function() {
        const currRating = parseInt($(this).data('value'), 10);
        $(this).parent().children('li.star').each(function(index) {
          $(this).toggleClass('selected', index < currRating)
        });
        const last = $(this).parent().find('li.selected').last();
        if (opts.callback) opts.callback(parseInt(last.data('value'), 10));
      }
    });
  };
})(jQuery);

$('.rating-stars').ratingWidget({
  callback: responseMessage
});

function responseMessage(rating) {
  var msg = rating > 1
    ? `Thanks! You rated this ${rating} stars.`
    : `We will improve ourselves. You rated this ${rating} stars.`;
  console.log(msg);
}
/* Rating stars */
.rating-stars {
}

.rating-stars ul {
  display: flex;
  flex-direction: row;
  width: 100%;
  list-style-type: none;
  padding: 0;
  -moz-user-select: none;
  -webkit-user-select: none;
}

.rating-stars ul>li.star {
  cursor: pointer;
}

/* Idle State of the stars */
.rating-stars ul>li.star>i.fa {
  font-size: 2.5em;
  color: #ccc;
}

/* Selected and hovered state of the stars */
.rating-stars ul>li.star.selected.hover>i.fa {
  color: #2C91FF;
}

/* Selected state of the stars */
.rating-stars ul>li.star.selected>i.fa {
  color: #FF912C;
}

/* Hover state of the stars */
.rating-stars ul>li.star.hover>i.fa {
  color: #FFCC36;
}

.as-console-wrapper {
  max-height: 4em !important;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="rating-stars">
  <ul id="stars">
    <li class="star" title="Poor" data-value="1">
      <i class="fa fa-star fa-fw"></i>
    </li>
    <li class="star" title="Fair" data-value="2">
      <i class="fa fa-star fa-fw"></i>
    </li>
    <li class="star" title="Good" data-value="3">
      <i class="fa fa-star fa-fw"></i>
    </li>
    <li class="star" title="Great" data-value="4">
      <i class="fa fa-star fa-fw"></i>
    </li>
    <li class="star" title="Amazing" data-value="5">
      <i class="fa fa-star fa-fw"></i>
    </li>
  </ul>
</div>
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
0

$(##) expects DOM selector, not only class .star_1:

<div class="star_1"></div>

you pass selector star_1, so jQuery searches for that element

<start_1></star_1>

and it's most likely you use classes/id's but not custom elements, that's why it's not working.

Justinas
  • 41,402
  • 5
  • 66
  • 96
0

You are having $(sp_cls).toggleClass(sp_cls); where sp_cls='.star_color_1', so in case of selector $(sp_cls) it is correct but in parameter value for toggleClass you should pass value without dot (.). You can use sp_cls.slice(1) which will return string from 1st index.

Moreover $(sp_cls).toggleClass(sp_cls); will remove class from the element next time when it will come to this line $(sp_cls) will not find any matching element. You should consider using different class in toggleClass like active etc. - Just a suggestion though.

Second thing you should learn about closure. Here your code will start working with above code but when you click on element it will always have sp_cls as star_color_5 and i = 6.

To capture value you must declare i using let instead of var in for (let i = 1; i < 6; i++). Here are references

Your updated function would be like below.

for (let i = 1; i < 6; i++) {  
    var cls = ".star_".concat(i);
    var sp_cls = ".star_color_".concat(i);
    $(cls).click(function() {
        $(sp_cls).toggleClass(sp_cls.slice(1));
        $("#rate").html("<b>Hello world!</b>");
        console.log(i);
    });
}

Try it below.

for (let i = 1; i < 6; i++) {  
  var cls = ".star_".concat(i);
  var sp_cls = ".star_color_".concat(i);
  $(cls).click(function() {
    $(sp_cls).toggleClass(sp_cls.slice(1));
    $("#rate").html("<b>Hello world!</b>");
    console.log(i);
  });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<!-- Rating Stars Box -->
<div class='rating-stars text-center p-2 mt-3'>
  <h5 id="rate">Rate this answer here!</h5>
  <ul id='stars'>
    <li class='star_1' title='Poor' data-value='1'>
      <span class='star_color_1'>
        <i class='fa fa-star fa-fw fa-2x'></i>
      </span>
    </li>
    <li class='star_2' title='Fair' data-value='2'>
      <span class='star_color_2'>
        <i class='fa fa-star fa-fw fa-2x'></i>
      </span>
    </li>
    <li class='star_3' title='Good' data-value='3'>
      <span class='star_color_3'>
          <i class='fa fa-star fa-fw fa-2x'></i>
      </span>
    </li>
    <li class='star_4' title='Excellent' data-value='4'>
      <span class='star_color_4'>
        <i class='fa fa-star fa-fw fa-2x'></i>
      </span>
    </li>
    <li class='star_5' title='WOW!!!' data-value='5'>
      <span class='star_color_5'>
        <i class='fa fa-star fa-fw fa-2x'></i>
      </span>
    </li>
  </ul>
</div>
Karan
  • 12,059
  • 3
  • 24
  • 40