user3683666
user3683666

Reputation: 85

Javascript Countdown Not Iterating Inside C# Foreach Loop

I have written a foreach loop code to iterate through list of products (products are rotating via jquery content slider) and i want to add a javascript countdown inside this loop but the problem is the countdown only appears in the first product of this loop like below:

enter image description here

But when it iterates through other products it is not appearing

enter image description here

Here's my code i have written

<div id="rightBox">
        @foreach (var product in Model)
        {
            <div id="[email protected]" class="ui-tabs-panel" style="">
                <div style="float: right">
                    <div class="banner"></div>
                    <img class="img-content" src="~/Content/ProductImages/@product.Image" alt="" />
                </div>
                <div class="content">
                    <div class="column">
                        <span class="fa" style="text-decoration: line-through; font-size: 1.9rem">@product.MainPrice.ToString("N0") تومان</span>
                        <div style="margin: 10px 10px 10px 10px;"></div>
                        <span class="fa" style="color: #ef5661; font-size: 1.9rem">@string.Format("{0:N0}", product.DiscountPrice) تومان</span>
                    </div>
                    <div class="columnleft fa">
                        ٪@Math.Floor((1 - (product.DiscountPrice / product.MainPrice)) * 100)&emsp;
                        <span> تخفیف </span>
                    </div>
                    <div class="title">
                        <p>@product.Name</p>
                    </div>
                    <br />
                    <div class="desclist">
                        @Html.Raw(product.Description)
                    </div>
                    <div class="fa" style="bottom: 50px; position: absolute">
                        <hr />
                        <div class="fa" style="font-size: x-large">
                            <span class="fa" id="hrRemaining"></span>:<span id="minRemaining"></span>:<span id="secRemaining"></span>
                        </div>                            
                        <p>زمان باقیمانده تا پایان سفارش</p>
                    </div>
                </div>
            </div>
        }
    </div>

And this is javascript countdown code

<script>
        var remSeconds = Math.floor(@timeRemaining);
        var secondsCounter = Math.floor(remSeconds % 60);
        var minutesCounter = Math.floor((remSeconds / 60) % 60);
        var hoursCounter = Math.floor((remSeconds / 3600));

        function formatNumber(number) {
            if (number < 10)
                return '0' + number;
            else
                return '' + number;
        }

        function startTick() {
            document.getElementById('secRemaining').innerText = formatNumber((secondsCounter));
            document.getElementById('minRemaining').innerText = formatNumber((minutesCounter));
            document.getElementById('hrRemaining').innerText = formatNumber((hoursCounter));
            //document.getElementById('tRemaining').innerText = formatNumber((remSeconds));

            var _tick = setInterval(function () {
                if ((remSeconds) > 0) {
                    if (hoursCounter > 0) {
                        if (minutesCounter == 0) {
                            minutesCounter = 60;
                            hoursCounter = hoursCounter - 1;
                        }
                    }
                    if (secondsCounter == 0) {
                        secondsCounter = 60;
                        minutesCounter = minutesCounter - 1;
                    }
                    secondsCounter = secondsCounter - 1;
                    remSeconds = remSeconds - 1;

                    document.getElementById('secRemaining').innerText = formatNumber((secondsCounter));
                    document.getElementById('minRemaining').innerText = formatNumber(parseInt(minutesCounter));
                    document.getElementById('hrRemaining').innerText = formatNumber(parseInt(hoursCounter));
                    document.getElementById('clock').innerHTML = "Hello" + "<span class='fa' id='hrRemaining'>" + "</span>:<span id='minRemaining'></span>" + "<span id='secRemaining'></span>";
                    //document.getElementById('tRemaining').innerText = formatNumber(parseInt(remSeconds));
                } else {
                    clearInterval(_tick);
                    //document.getElementById("tRemaining").innerHTML = "EXPIRED";
                }
            }, 1000);
        }

        startTick();
    </script>

Upvotes: 0

Views: 245

Answers (2)

Tieson T.
Tieson T.

Reputation: 21231

The first, and primary issue, is that you have duplicate ID values in your rendered HTML. That's going to cause issues when you try selecting those elements with getElementById. So, let's fix that first:

<div id="rightBox">
    @foreach (var product in Model)
    {
        <div id="[email protected]" class="ui-tabs-panel" style="">
            <div style="float: right">
                <div class="banner"></div>
                <img class="img-content" src="~/Content/ProductImages/@product.Image" alt="" />
            </div>
            <div class="content">
                <div class="column">
                    <span class="fa" style="text-decoration: line-through; font-size: 1.9rem">@product.MainPrice.ToString("N0") تومان</span>
                    <div style="margin: 10px 10px 10px 10px;"></div>
                    <span class="fa" style="color: #ef5661; font-size: 1.9rem">@string.Format("{0:N0}", product.DiscountPrice) تومان</span>
                </div>
                <div class="columnleft fa">
                    ٪@Math.Floor((1 - (product.DiscountPrice / product.MainPrice)) * 100)&emsp;
                    <span> تخفیف </span>
                </div>
                <div class="title">
                    <p>@product.Name</p>
                </div>
                <br />
                <div class="desclist">
                    @Html.Raw(product.Description)
                </div>
                <div class="fa" style="bottom: 50px; position: absolute">
                    <hr />
                    <div class="fa countdown-timer" style="font-size: x-large">
                        <span class="fa hrRemaining"></span>:<span class="minRemaining"></span>:<span class="secRemaining"></span>
                    </div>                            
                    <p>زمان باقیمانده تا پایان سفارش</p>
                </div>
            </div>
        </div>
    }
</div>

I've replaced your id attributes with classes, which we can leverage in the code I'll add below.

Since you've tagged this with jQuery, I've re-written your example to use jQuery rather than vanilla JavaScript:

var remSeconds = Math.floor(@timeRemaining);
var secondsCounter = Math.floor(remSeconds % 60);
var minutesCounter = Math.floor((remSeconds / 60) % 60);
var hoursCounter = Math.floor((remSeconds / 3600));

function formatNumber(number) {
    if (number < 10)
        return '0' + number;
    else
        return '' + number;
}

function startTimers(){

    // The variables prefixed with `$` represent jQuery objects. Using $ isn't necessary, but it 
    // makes it a bit more obvious that it's not a "data" variable

    // This will select all elements with the class 'countdown-timer'
    var $timers = $('.countdown-timer');

    // See https://api.jquery.com/each/
    $timers.each(function(){
        // `this` is the current `.countdown-timer` being iterated by jQuery.each()
        var $timer = $(this);

        var $seconds = $timer.find('.secRemaining');
        var $minutes = $timer.find('.minRemaining');
        var $hours = $timer.find('.hrRemaining');

        $seconds.text(formatNumber((econdsCounter));
        $minutes.text(formatNumber(minutesCounter));
        $hours.text(formatNumber(hoursCounter));

        var _tick = setInterval(function () {
            if (remSeconds > 0) {
                if (hoursCounter > 0) {
                    if (minutesCounter == 0) {
                        minutesCounter = 60;
                        hoursCounter = hoursCounter - 1;
                    }
                }

                if (secondsCounter == 0) {
                    secondsCounter = 60;
                    minutesCounter = minutesCounter - 1;
                }

                secondsCounter = secondsCounter - 1;
                remSeconds = remSeconds - 1;

                $seconds.text(formatNumber((econdsCounter));
                $minutes.text(formatNumber(minutesCounter));
                $hours.text(formatNumber(hoursCounter));                    
            } else {
                clearInterval(_tick);
                //document.getElementById("tRemaining").innerHTML = "EXPIRED";
            }
        }, 1000);
    }
}

startTimers();

So, a review of the changes:

  • I added a class called countdown-timer to the <div> elements which you use to contain your hours, minutes, and seconds elements.
  • I switched the id attributes for class attributes, which lets us re-use our "selectors" - the classes that identify our timer elements
  • I renamed the function to startTimers, but that's just because (to me) it more accurately describes the function's usage.
  • Within startTimers, I use jQuery to select each of the timer elements (denoted by countdown-timer), which will return something I can treat as an array.
  • I then use the $('selector').each() function to iterate through the array of timers, setting the matching element's text values and kicking off the setInterval loops.

Upvotes: 1

shaunteezie
shaunteezie

Reputation: 89

This is because you are using an id. Ids must be unique in HTML. If each of these items have the same time remaining, then just change the ids to a class. If they are unique countdowns then you should probably add them to your model and generate a unique id for each product. Then obviously you would need to modify your javascript to keep track of the ids.

Upvotes: 1

Related Questions