What techniques can be used to create a more streamlined progress bar in coding?

Adding a progress bar has been a bit tricky for me - sometimes it fills too slowly or too quickly, but for the most part, it works fine.

I believe there must be a more efficient way to program this since my current method involves too many calculations for just one progress bar.

Below is the code I am using:

ts:

startProgressbar(timeToWait: number) {
this.progress = 0;
const interval = setInterval(() => {
  let addvalue = (1 / timeToWait * 100) / 64;
  this.progress += addvalue;
  if (this.progress >= 100) {
    this.progress = 100;
    window.clearInterval(interval);
  }
}, 15.625); }

The function is called again immediately after completion because the next slide of the slideshow follows.

The value of the progress reflects the width of the progress bar, always in percentage form.

Wondering about the number 15.625? It represents a 64th of a second, allowing the progress bar to update smoothly 64 times per second.

My HTML structure is quite simple:

<div class="progressbar" [ngStyle]="{'width': progress+'%'}"></div>

If you have a better solution than mine, I would greatly appreciate it. Thank you!

[EDIT]: Sometimes the progress bar starts filling late and does not reach 100% before the next slide appears, causing timing issues. Other times it fills up too quickly and remains at 100% until the next slide loads.

Answer №1

Why not consider using Rxjs timer?

interval(timeToWait):Observable<number>
  {
    let progress = 0;
    return timer(0, timeToWait)
      .pipe(
        takeWhile(() => progress <= 100),
        map(()=>progress<100?progress:100),
        tap(() => (progress += 10))
      )
  }

Implementation:

this.interval(200).subscribe((res) => {
        console.log(res);
      });

Update: Added stackblitz demo link: stackblitz

Update 2: Special thanks to @Ritaj for the insight that timer returns a stream (0,1,2,3,4,...), allowing us to simplify with:

 return timer(0, timeToWait)
  .pipe(
    map((progress)=>progress*5<100?progress*5:100),
    takeWhile((progress) => progress <= 100)
  )

Update 3: Following advice from this insightful response on SO, we can now include the last value by modifying the interval function as follows:

 interval(timeToWait) {
    const initial = new Date().getTime();
    return timer(0, 200).pipe(
      map(()=> new Date().getTime()),
      takeWhile((res) => res<=initial+timeToWait,true),
      map(now=>{
        const porc = (100 * (now - initial)) / timeToWait;
        return porc<100?Math.round(porc):100
      })
    );

Answer №2

For efficient waiting in Javascript, I highly recommend following the best practices outlined here. Take a look at this StackBlitz link where I have provided example code for a progress bar that implements these recommended practices.

export class AppComponent  {
  name = 'Angular';
  public progress = 0;
  public timeToWait: number = 1;

  private default_ms = 8.33; // Running 120 times a second.
  private sleep(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  public async startProgressBar(): Promise<void> {
    this.progress = 0;
    while(this.progress <= 100) {
      this.progress += (1 / this.timeToWait);
      await this.sleep(this.default_ms);
    }
  }
}

It's hard to pinpoint exactly why your current solution is encountering bugs. It may not be ideal practice to call window.clearInterval within the interval function. Feel free to give this solution a try and let me know if it resolves your issue.

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

What is the best way to retrieve a property from a conditional type using generics?

The code snippet above presents an issue in TypeScript: const exampleFn = function<AttributeName extends 'attributeA' | 'attributeB'>( whatToProcess: AttributeName extends 'attributeA' ? {attributeA: string} : {attri ...

Access the system by authenticating with the Firestore database collection

My goal is to develop a function that retrieves information from my collection in order to log into my application. With the help of this service, I am able to fetch all the necessary data: getUsersLocal(): Observable<AdminUser[]> { const bo ...

Encountering issues with fs.readFileSync when used within a template literal

For some reason, I am encountering an error when trying to read a file using fs.readFileSync within a Template literal. The specific error message that I'm getting is: Error: ENOENT: no such file or directory, open './cookie.txt' at Obje ...

Creating a custom directive in Angular that dynamically applies attributes based on the current route

I have been able to successfully set the attribute data-toggle-state to both active and inactive using the following code: <a [routerLink]="['/home']" [attr.data-toggle-state]="router.isActive('/home', true) ? 'active' : ...

Angular6 returns the result after subscribing to an HTTP POST request

Currently, I am in the process of learning angular and attempting to create a component that allows users to register through my web API. Within my component, the code on form submission looks like this: onSubmit(contactFormRef: NgForm) { const resu ...

There is an issue with the Angular Delete request functionality, however, Postman appears to be

HttpService delete<T>(url: string): Observable<T> { return this.httpClient.delete<T>(`${url}`); } SettingsService deleteTeamMember(companyId: number, userId: number): Observable<void> { return this.httpService.delete< ...

Creating a unique abstract element for cycling through a collection

I have multiple components that all have a similar structure: import { Component, Input, Output } from '@angular/core'; import { Subject } from 'rxjs'; import { Tag } from 'src/app/models'; @Component({ selector: 'app ...

Encountered an issue with the node-mssql error message while attempting a bulk insert: "A premature end-of-message was encountered while reading the current row from the host."

While attempting to utilize the .bulk operation within the node-mssql library in node.js, an error message is being returned: While reading current row from host, a premature end-of-message was encountered--an incoming data stream was interrupted when th ...

What is the process for integrating Mocha into a create-react-app project that uses Typescript?

I have been working on a react application using create-react-app (typescript) and found that I prefer using mocha + enzyme for testing my React components instead of jest. In the past, I used the following test script: "test" :"NODE_ENV=development m ...

The BeanStub initialization failed due to a missing bean reference to frameworkOverrides

I recently updated my ag-grid version to 23.2.0 in my Angular 7 project. Everything was working fine, but when I tried filtering a page and then navigating away, I encountered the following error message: "unable to find bean reference frameworkOverrides ...

Steps to perform a task that relies on two observables

I'm currently working on a function that requires two responses from two separate asynchronous functions, both returning observables. 1. Func1 returns an observable 2. Func2 returns an observable These functions are independent and can be executed sep ...

Retrieve a specific key from a TypeScript interface

It seems like there might be a problem with this code snippet: interface import {BrowserService} from "../services/browser/index"; export interface IPrimaryNavigation { opts:IPrimaryNavigationOpts; } export interface IPrimaryNavigationOpts { .. ...

Troubleshooting: Angular 2 ngIf not functioning properly when using properties in extended classes

I have developed an angular 2 component for a modal that inherits from a base modal class. The base class contains a boolean property to determine if the modal is open or closed, which I am utilizing in the template with *ngIf to toggle the visibility of t ...

Is it true that core JavaScript is not compatible with AngularJS projects?

While this may seem like a simple question to some, I have been struggling to find the answer for quite some time now. Why is it that native javascript methods like onclick do not work in my Angular 2 project? Below is a sample code snippet for reference: ...

When evaluating objects or arrays of objects to determine modifications

How can we detect changes in table data when users add input to cells? For example, if a user clicks on a cell and adds an input, the function should return TRUE to indicate that there are changes. If the user just clicks on the cell without making any ch ...

The element 'flat' is not found within the specified type

My challenge involves utilizing the flat() method in a TypeScript script. In my tsconfig.json file, I have set the target to es2017 and defined an interface for the input variable. However, I keep encountering this error message: Property 'flat' ...

Utilizing import for Ionic3 to export const with logic

While developing an app using ionic3, I encountered an issue with setting up a proxy. When running in a browser, Ionic was able to recognize the path of my proxyUrl as shown below. ionic.config.json { "name": "myApp", "app_id": "", "v2": true, "t ...

Encountering a TypeScript issue with bracket notation in template literals

I am encountering an issue with my object named endpoints that contains various methods: const endpoints = { async getProfilePhoto(photoFile: File) { return await updateProfilePhotoTask.perform(photoFile); }, }; To access these methods, I am using ...

Propagation of data within singleton services

Working with different components and a shared service, my setup involves one component rendering array items from the service, while another displays the array's length. I started questioning my understanding of singletons: A singleton service is ...

What steps can be taken to troubleshoot the error message "InjectionToken angularfire2.app.options! not found" during testing of Firestore in Angular?

During my Angular test, I encountered an issue with a component and a service that utilizes Firestore. Here is the error message from my ItemService: NullInjectorError: R3InjectorError(DynamicTestModule)[ItemService -> AngularFirestore -> InjectionTo ...