Is there a way to accurately retrieve the width of an element within setInterval without any delay?

I'm currently experimenting with increasing a progress bar using the setInterval function. So far, it seems to be functioning properly.

var progressBar = $('.progress-bar');

var count = 0;

var interval = setInterval(function () {
    var width = progressBar.width();

    console.log(width++);

    progressBar.width(width);

    count++;

    if (count === 101) {
      clearInterval(interval);
    }
}, 50);
.progress-bar {
  width: 0px;
  height: 4px;
  background-color: #00f;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

<div class="progress-bar"></div>

However, when I tried nesting it into a dropdown, I encountered issues with the timing of repeating actions:

var increase = function (progressBar, ms) {
    var count = 0;

    var interval = setInterval(function () {
        var width = progressBar.width();

        console.log(width++);

        progressBar.width(width);

        count++;

        if (count === 21) {
          clearInterval(interval);
        }
    }, ms);
}

$('.dropdown').on('shown.bs.dropdown', function () {
    var progressBar = $(this).find('.progress-bar');
    
    increase(progressBar, +progressBar.data('ms'));
});
.progress-bar {
  width: 0px;
  height: 4px;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="92e2fde2e2f7e0bcf8e1d2a3bca3a4bca2">[email protected]</a>/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>

<div class="dropdown d-inline-block">
  <button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
    Progress bar with 100ms
  </button>
  <div class="dropdown-menu" >
    <a class="dropdown-item" href="#">
        <div class="progress-bar" data-ms="100"></div>    
    </a>
  </div>
</div>

<div class="dropdown d-inline-block">
  <button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
    Progress bar with 300ms
  </button>
  <div class="dropdown-menu">
    <a class="dropdown-item" href="#">
        <div class="progress-bar" data-ms="300"></div>    
    </a>
  </div>
</div>

Upon expanding the dropdown, the width of the progress bar increases. However, I've noticed that different values for repetition intervals yield unexpected results.

In this scenario, setting the value to 100 or lower leads to inaccurate width increments. The initial width value is 0, but after increasing by 1, why does it become 0.15625 and then 0.3125...?

On the other hand, when the value is set to 300 or higher, the width increments correctly (0, 1, 2...)

Any insights on why this is happening?

Answer №1

It's recommended to utilize the CSS width property instead of jQuery's width() method as width() may provide inaccurate data.

var increase = function (progressBar, ms) {
    var count = 0;
    var interval = setInterval(function () {
        var width = parseInt(progressBar[0].style.width) || 0;
        console.log(width++);
        progressBar[0].style.width = `${width}px`;
        count++;
        if (count === 21) {
          clearInterval(interval);
        }
    }, ms);
}

$('.dropdown').on('shown.bs.dropdown', function () {
    var progressBar = $(this).find('.progress-bar');
    
    increase(progressBar, +progressBar.data('ms'));
});
.progress-bar {
  width: 0px;
  height: 4px;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="19697669697c6b37736a592837282f3729">[email protected]</a>/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>

<div class="dropdown d-inline-block">
  <button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
    Progress bar with 100ms
  </button>
  <div class="dropdown-menu">
    <a class="dropdown-item" href="#">
      <div class="progress-bar" data-ms="100"></div>
    </a>
  </div>
</div>

<div class="dropdown d-inline-block">
  <button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
    Progress bar with 300ms
  </button>
  <div class="dropdown-menu">
    <a class="dropdown-item" href="#">
      <div class="progress-bar" data-ms="300"></div>
    </a>
  </div>
</div>

Referencing information from the documentation:

Keep in mind that .width() will always return the content width, regardless of the value of the CSS box-sizing property. As of jQuery 1.8, this might involve fetching the CSS width along with the box-sizing property and then deducting any potential border and padding on each element when the element has box-sizing: border-box. To avoid this issue, opt for .css( "width" ) rather than .width().

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Adjusting element position while scrolling

Objective The goal is to have the page navigation display lower on the page by default. This will provide a cleaner layout as shown in the image below. Context An interactive element for navigation was implemented utilizing Headroom.js. This library d ...

The bug in Polymer 1.0 where a custom element is causing issues when clicking under the toolbar

Issues have arisen with a custom element I created, named <little-game></little-game>. Here is the template code for <little-game></little-game>: <template> <a href="{{link}}"> <paper-material elevation=& ...

What value is used as the default for justify content?

MDN states that the default value of justify-content is normal, even though it's not listed in the accepted values. What exactly does a normal value mean? normal This means that items are packed in their default position as if no justify-cont ...

The percentage height setting for a div is not functioning properly, but setting the height in pixels or viewport

Within a dialog box body, I am attempting to display a table and have applied a CSS class to the wrapping div. When specifying the height in pixels or viewport height units, it works as expected. However, when using a percentage like 50%, the height of the ...

What is the best way to define the scope of an HTTP request within my application?

I need assistance with setting the scope for an http request in my Ionic App. Our Backend is built with Node.JS using the Hapi Framework. Since I primarily work on the frontend, I lack knowledge of server-side operations. Currently, I am able to successfu ...

AJAX request receives a Flask 404 response

I'm currently facing a challenge in getting my Flask application to properly handle a straightforward AJAX request. The issue seems to be related to sending the request to the correct address. Within my app.py file, I've set up a basic route and ...

The map function appears to be malfunctioning or there may be an issue with the retrieved data

Encountering an error message that says "Cannot read properties of undefined (reading 'map')" while attempting to render a list. Below is the code snippet, seeking assistance. import React, { Component } from 'react' // import axios fro ...

"Embracing Dynamism: Enhancing Vue3 with Dynamic Routing for

Seeking guidance on implementing a dynamic component with Dynamic Routing in Vue3. The goal is to render a component based on the parameter (path named id) from router.ts. In the router.ts file, there is a dynamic parameter called id that needs to be used ...

JavaScript and the importance of using commas in arrays

I am developing a system that displays text in a textarea when a checkbox is checked and removes the text when the checkbox is unchecked. The functionality is mostly working as intended, but I am facing an issue where commas remain in the textarea after un ...

Why is it possible for me to call a function that is defined below a component?

My understanding was that in Javascript, functions could not be invoked if they are defined below where they're called (unless hoisting is involved). However, I discovered something interesting while working with React. The code snippet below actuall ...

A contact form overlaying a muted Google Maps view in an HTML website

Currently, I am in the process of developing a website that features a contact form. It would be great if I could incorporate Google Maps as a background, but with a greyed-out effect instead of a plain white page. After trying out a few solutions, I ende ...

Is Your Website Sluggish because of an Excessive Amount of JavaScript on Page

After finally resolving some of the Javascript issues I was facing, I have streamlined my code to utilize just one library now, which is a huge improvement from how chaotic it was before. However, I have noticed a slight delay in the page load time, and I ...

Display the div when scrolling downwards beyond 800px

Is there a way to display a hidden section when scrolling down the page, specifically after reaching a point 800px from the top? I currently have an example code that may need some modifications to achieve this desired effect. UPDATE: [Additionally, when ...

Utilizing v-if and splice on users to select items from v-model

After following a tutorial, I have the code snippet below that I would like to enhance: <div style="margin-top: 10px;"> v-for="task in taskItems" :key="task.id" <q-icon :name="task.icon"/> <div ...

Creating a peaceful web platform with React that supports several user roles

I am in the process of developing a single-page web application that must be completely restful, which is new territory for me. One challenge I'm facing is determining how to efficiently render the user interface for different roles using React. With ...

Click on the div to automatically insert its text into the textarea

I am looking for a way to enable users to edit their posts easily. My idea is to have them click on a link, which will then hide the original div containing their post and reveal a new div with the old text inside a textarea for editing. Despite searching ...

A mysterious JavaScript snippet that automatically scrolls down when the webpage is loaded

Recently, I encountered an issue with a mysterious JavaScript script that automatically scrolls down when entering the page (I suspect it's JavaScript). I've tried to investigate using Firebug, examining the code, deleting scripts, and even remov ...

Assign specific CSS classes to elements based on the v-model value in Vue.js

Looking to create a dynamic table using Vue and trying to add a class to a row when a checkbox is checked. Each checkbox is associated with a specific value in an object of objects. View the code on Codepen. <tbody> <tr v-for="row in filter ...

Is there a way for me to update the button text and class to make it toggle-like

Is there a way to switch the button text and class when toggling? Currently, the default settings show a blue button with "Show" text, but upon click it should change to "Hide" with a white button background. <button class="btn exam-int-btn">Show< ...

Exploring how to locate an item in an array using its id with Underscore

Here is an array of objects showcasing equipment images: var jsonarray = [{ "id": "6", "equipment_img": "http://xxx:9696/XXX/images (1)_410.jpg" }, { "id": "7", "equipment_img": "http://xxx:9696/XXX/5.jpg" }, { "id": "8", "equipmen ...