javascriptjqueryasp.net-mvcjavascriptmvc

calling JavaScript function inside foreach loop


I have rating-stars, using foreach need to addClass depends on the value been passed from the model. i.e. if 2 (then first 2 stars class rated is applied)

 foreach (var rev in Model.Reviews)
 {
   <p class="rating">  
   <span id="5" class="fa fa-star"></span>
   <span id="4" class="fa fa-star"></span>
   <span id="3" class="fa fa-star"></span>
   <span id="2" class="fa fa-star"></span>
   <span id="1" class="fa fa-star"></span>
   </p>

   <script>
       apply(@rev.Rating);
   </script>
 }

apply function:

 <script type="text/javascript">
           function apply(r) {
               $('.rating span').each(function () {
                    if (this.id <= r) {
                        $(this).addClass("rated");
                    }
                });
            }
  </script>

The problem for example: when rev.Rating is 2, the addClass is applied correctly to two ids. But then when next value is 4 it overrides the first and it applies addClass to 4 stars and then next is 4 stars.

the issue it overrides the previous stars with the current model value.

I think because the p class="rating" is the same. But I thought if I pass (this) current reference it shouldt override the other elements. Any ideas why? and How I can fix it.

using this code inside a view, using MVC


Solution

  • Yes the problem is your use of apply method, you can have a single dom ready callback which will update the rated class like below.

    In each rating element, you can store its initial value using a data-* value, which can be used in a dom ready handler after the loop.

    Also since ID of an element must be unique, you can use another data-* attribute to store the value of the span

    jQuery(function($) {
      $('.rating').each(function() {
        $(this).find('span').slice(-$(this).data('default-value')).addClass("rated");
      });
    })
    .rated {
      border: 1px solid red;
    }
    <p class="rating" data-default-value="2">
      <!-- data-default-value="@rev.Rating" -->
      <span data-value="5" class="fa fa-star"></span>
      <span data-value="4" class="fa fa-star"></span>
      <span data-value="3" class="fa fa-star"></span>
      <span data-value="2" class="fa fa-star"></span>
      <span data-value="1" class="fa fa-star"></span>
    </p>
    <p class="rating" data-default-value="4">
      <span data-value="5" class="fa fa-star"></span>
      <span data-value="4" class="fa fa-star"></span>
      <span data-value="3" class="fa fa-star"></span>
      <span data-value="2" class="fa fa-star"></span>
      <span data-value="1" class="fa fa-star"></span>
    </p>


    So

    foreach (var rev in Model.Reviews)
     {
       <p class="rating" data-default-value="@rev.Rating"> 
           <span id="5" class="fa fa-star"></span>
           <span id="4" class="fa fa-star"></span>
           <span id="3" class="fa fa-star"></span>
           <span id="2" class="fa fa-star"></span>
           <span id="1" class="fa fa-star"></span>
       </p>
     }
    <script>
        jQuery(function ($) {
            $('.rating').each(function () {
                $(this).find('span').slice(-$(this).data('default-value')).addClass("rated");
            });
        })
    </script>