Ways to display an SVG spinner prior to a substantial UI refresh

I am currently facing an issue with updating 10 apexcharts bar charts simultaneously in a Vue app. When this process occurs, it takes approximately one second to load completely, and during that time, I would like to display an svg spinner. However, the conventional method of using a v-if="showSpinner" on a div containing the spinner, and setting showSpinner.value = true for const showSpinner = ref(false) does not seem to be effective. Here is an example:

<template>
    <div v-if="showSpinner">
       [svg spinner]
    </div>
    <div>
       [10 apexcharts being updated at once with existing data]
    </div>
</template>

<script setup lang="ts">

import { ref, nextTick } from 'vue';

const showSpinner = ref(false);
const state = reactive({
    dataForCharts: {},
});

const someFuncThatGetsCalledMuchLater = () => {
    showSpinner.value = true;

    nextTick(() => {
        // code to modify state.dataForCharts and redraw the charts   
    });
}

</script>

Even without considering the code needed to eventually set showSpinner.value = false (which presents another challenge), the above code fails to display the spinner until after all the charts have finished updating, seemingly causing the webpage to freeze for a second due to JavaScript's single-threaded nature.

Therefore, my main concerns are:

  1. How can I ensure the svg spinner appears before the chart updates begin, preventing the webpage from freezing?
  2. I haven't reached this point yet as the first concern remains unresolved, but how can I detect a callback signaling the completion of the chart updates? Directives do not seem suitable since they only act on attached elements, and setting showSpinner.value = false within onUpdated(...) would likely negate the prior showSpinner.value = true assignment.

Answer №1

1. Display loading spinner before rendering charts

If you want to show a spinner before rendering the charts, you can update the showSpinner variable first, then trigger a redraw, and finally render the charts using Vue's nextTick function.

import { ref, nextTick } from 'vue';

const someFuncThatGetsCalled = async () => {
  showSpinner.value = true;
  await nextTick();
  state.dataForCharts = updatedData;
}

The use of nextTick allows you to wait for the DOM updates to complete before proceeding with further JavaScript execution, ensuring a smooth rendering process.

In case the browser fails to re-render after the updates, you can manually delay the heavy JS operations until after the initial changes have been rendered using methods like setTimeout or nested requestAnimationFrame calls.

async function waitForRender(){
  return new Promise((resolve)=>{
    requestAnimationFrame(()=>{
      requestAnimationFrame(()=>{
        resolve()
      })
    })
  })
}

You can then integrate this function into your code:

const someFuncThatGetsCalled = async () => {
  showSpinner.value = true;
  await waitForRender();
  state.dataForCharts = updatedData;
};

2. Monitoring the Mounting of Charts

ApexCharts allows you to define event handlers within the chart configuration options, such as the mounted event, which notifies when a chart has been successfully mounted.

Ensure each chart has an event listener that increments a counter, allowing you to track when all charts have been loaded.

const chartsLoaded = ref(0);

const chartOptions = {
  chart: {
    id: "bar-shart",
    events: {
      mounted() {
        chartsLoaded.value ++;
      }
    },
    // other configurations...
  },
  // additional settings...
}

const someFuncThatGetsCalled = async () => {
  showSpinner.value = true;
  await waitForRender();
  state.dataForCharts = initialData;
}

watch(chartsLoaded, (num) => {
  if (num === totalCharts) {
    console.log("All charts loaded successfully!");
    showSpinner.value = false;
  }
})

Make sure to include proper event handling mechanisms according to the compatibility of ApexCharts with different versions of Vue, such as the usage of @mounted in Vue 3.

const chartsLoaded = ref(0);

function onChartMounted(){
  chartsLoaded.value ++;
}

const someFuncThatGetsCalled = async () => {
  showSpinner.value = true;
  await waitForRender();
  state.dataForCharts = initialData;
}

watch(chartsLoaded, (num) => {
  if (num === totalCharts) {
    console.log("All charts loaded successfully!");
    showSpinner.value = false;
  }
})

Template:

<apex-chart :options="chartOptions" :series="chartSeries" @mounted="onChartMounted" />

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

The glitch in VueJS's array updating functionality

I am facing an issue where I have an array called tiles with a title. On creating the instance, I add a field to this array named active. Subsequently, I display this array within an <li> element and iterate through it to display the title and activ ...

Steps for replacing the firestore document ID with user UID in a document:

I've been attempting to retrieve the user UID instead of using the automatically generated document ID in Firebase/Firestore, but I'm encountering this error: TypeError: firebase.auth(...).currentUser is null This is the content of my index.js ...

Cross domain request in a simple HTML document

I'm currently working on an app that is strictly in plain HTML files without a server. I'm facing difficulties with cross domain requests from JavaScript. Whenever I try to make a request, the browser displays this error message: XMLHttpRequest ...

Managing input jQuery with special characters such as 'ä', 'ö', 'ü' poses a unique challenge

Hey there, I'm running into a bit of trouble with my code and I can't figure out why it's not working. Here's a brief overview: I created my own auto-suggest feature similar to jQuery UI autosuggest. Unfortunately, I'm unable t ...

Executing VueJS keyup handler after the previous onclick handler has been executed

Link to example code demonstrating the issue https://codepen.io/user123/pen/example-demo I am currently facing an issue with a text field named search_val that has a watcher attached to it. The text field includes a v-on keyup attribute to detect when th ...

Guide on automatically removing a DOM element in Jquery after a set amount of time

Is there a way to delete an HTML element after a specific period of time? If a certain condition is met before the allotted time, I want to pause the timer from deleting the element. Here's a snippet of code for reference: <ul> <li dat ...

Arranging divs in a horizontal line while keeping the content organized in a vertical manner within the footer

I've been searching for a while now, but I haven't found any solutions that actually work. This might be repetitive, so my apologies in advance. The issue at hand is aligning three divs horizontally to create a footer, while maintaining a vertic ...

Aligning list items with Bootstrap

I am struggling with aligning Sheet3 and Science vertically left in a list with checkboxes. Currently, Science goes below the checkbox and I need a solution to fix this alignment issue. https://i.sstatic.net/bxoBT.png Any guidance on how to adjust the al ...

Failed to install NPM

I just updated my nodejs to the latest version on Windows. However, when I try to install packages with the npm install command, it installs some packages but then gives me an error. npm WARN optional Skipping failed optional dependency /chokidar/fsevent ...

Issues are occurring with the @font-face css for the Futura Bk BT Bok.ttf font file

Is there a way to incorporate the 'Futura Bk BT Bok.ttf' font into my website using the CSS @font-face rule? Here is a snippet of my current CSS: @font-face { font-family: abcd; src:url('Futura Bk BT Bok.ttf') format('true ...

Step-by-step guide on programmatically activating a radio button

I am working with a radio button and input field. I need the ability to programmatically toggle the radio button so that when this.iAreaOfCoverageForThresholdPasser.average-height is set to true, the radio button appears highlighted. Snippet of HTML: < ...

Error encountered when attempting to initiate a second screenshare on Chrome due to an invalid state

I am interested in utilizing Screensharing in Chrome. After following a guide and creating an extension to access the deviceId for getUserMedia, I was able to successfully start streaming my screen. However, when I attempted to stop the stream using the pr ...

Arranging an Array Object in Javascript by Date

Although similar questions have been addressed in other posts, my specific situation appears to be unique due to the data I am receiving from Twitter. Here is the logic I am currently using to sort the JavaScript Array object. However, the issue seems to ...

Vue3 compilation error: Every single file component must include at least one <template> or <script> block

Attempting to update a large existing codebase from Vue2 to Vue3 with the help of Webpack. I have successfully upgraded the necessary packages in package.json, which now looks like this (no issues encountered): "vue": "^3.2.45", "@vue/compat": "^3.2.45", " ...

PHP encountered an issue when retrieving a value from a URL and passing it to a JavaScript variable

How can I pass a PHP variable from the URL using $_REQUEST to JavaScript in order to send it through Ajax? Here is the code snippet at the top of my page: <?php include_once('../php/connection.php'); include_once('../php/getDiagnosi ...

Is it feasible to utilize VAST for delivering HLS streams? Can m3u8 files be incorporated into VAST tags for delivery?

We are integrating a video player that supports VAST pre-roll, mid-roll, and post-roll video ads. I'm wondering if it's feasible to include m3u8 files in VAST tags? I've reviewed the vast specification and examples, but haven't come ac ...

The code attempted to use `app.set`, but received a TypeError because `app.get` is

While working with express 4.x, I encounter an issue with setting the port in my server.js file like this: var express = require('express'); var app = express(); ... var port = process.env.PORT || 8080; app.set('port', port); ... modul ...

Struggling to click on a dynamic link before it times out

Can someone help me with a puzzling issue I can't seem to solve? I am trying to achieve the following: Whenever a link is clicked (for example: mysite.com/blog/blog-article.html), I want to save the href of that link to a variable. Then, in JavaScri ...

What could have caused these errors, since they never made an appearance?

'Link' component cannot be utilized within JSX. The type 'ForwardRefExoticComponent<LinkProps & RefAttributes<HTMLAnchorElement>>' is not a valid element for JSX. The type 'ForwardRefExoticComponent<LinkPro ...

Having trouble getting two components to return in React

After successfully implementing the Hello World example by returning "Hello" and "world" from two different components, I encountered a problem with my code. In this specific code snippet, I am unable to return the Menubar component, although the Map compo ...