Delaying the intensive rendering process in Vue.js and Vuetify: A comprehensive guide

Recently, while working on a project with Vue.js 2 and Vuetify 2.6, I encountered an issue with heavy form rendering within expansion panels. There seems to be a slight delay in opening the panel section upon clicking the header, which is most likely due to the initial rendering process. Although the delay doesn't disrupt functionality, I would like to incorporate a progress indicator that displays instantly while the rendering takes place. Strangely, the progress indicator only shows up once the rendering is complete, even though the UI remains responsive during this time.

Is there a method to postpone the rendering of the panel section so that the progress indicator can first be displayed? Interestingly, the interface isn't unresponsive while the rendering occurs, allowing for the smooth animation of the progress indicator.

Unfortunately, utilizing the "eager" option for expansion panels is not feasible as it significantly slows down the loading time when dealing with numerous panels.

The provided code snippet presents this issue through a demonstrative example.

new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  data: () => ({
    loading: false
  }),
  methods: {
    click() {
      console.log('click')
      this.loading = true
    }
  }
})
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a3d5d6c6e3918ddb">[email protected]</a>/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="bdcbc8d8c9d4dbc4fd8f938b938c">[email protected]</a>/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a9dfdcccddc0cfd0e99b879d879d">[email protected]</a>/dist/vuetify.min.css">


<v-app id="app">
  <template>
    <v-expansion-panels>
      <v-expansion-panel @click="click">
        <v-expansion-panel-header>
          <template v-slot:default="{ open }">
            <span>
              <v-progress-circular
                v-if="loading"
                indeterminate
                size="14"
                width="2"
                color="blue"
                class="d-inline-block"
              />
            </span>
            <span>Click me! opened: {{ open }}</span>
          </template>
        </v-expansion-panel-header>
        <v-expansion-panel-content>
          <v-text-field v-for="(item, i) in 1500" :key="i" />
        </v-expansion-panel-content>
      </v-expansion-panel>
    </v-expansion-panels>
  </template>
</v-app>

Answer №1

The issue arises from the fact that the changes triggered by the loading flag (such as displaying the spinner and panel contents) are happening within the same macro tick.

A potential solution is to divide the effects into two distinct groups: (1) toggling the loading flag to show the spinner and open the panel, and (2) toggling a new flag to display the panel contents. This approach allows for shifting the second group of effects to the next macro tick:

  1. Introduce a Boolean flag as a data property and use it to conditionally render the panel contents.

  2. In the click handler, await the next macro tick (e.g., by using a setTimeout() without a timeout parameter).

  3. Toggle the flag created in step 1 to display the panel contents.

<script>
new Vue({
  data: () => ({
    1️⃣
    loadTextfields: false,
  }),
  methods: {
    async click() {
      this.loading = true
      2️⃣
      await new Promise(r => setTimeout(r))
      3️⃣
      this.loadTextfields = true
    }
  }
})
</script>
<v-expansion-panels>
  <v-expansion-panel @click="click">
    ⋮
    <v-expansion-panel-content>
                           1️⃣
      <template v-if="loadTextfields">
        <v-text-field v-for="(item, i) in 1500" :key="i"/>
      </template>
    </v-expansion-panel-content>
  </v-expansion-panel>
</v-expansion-panels>

new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  data: () => ({
    loading: false,
    loadTextfields: false,
  }),
  methods: {
    async click() {
      console.log('click')
      this.loading = true
      await new Promise(r => setTimeout(r))
      this.loadTextfields = true
    }
  }
})
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8dfbf8e8cdbfa3f5">[email protected]</a>/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="cabcbfafbea3acb38af8e4fce4fb">[email protected]</a>/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="27515242534e415e671509130913">[email protected]</a>/dist/vuetify.min.css">


<v-app id="app">
  <template>
    <v-expansion-panels>
      <v-expansion-panel @click="click">
        <v-expansion-panel-header>
          <template v-slot:default="{ open }">
            <span>
              <v-progress-circular
                v-if="loading"
                indeterminate
                size="14"
                width="2"
                color="blue"
                class="d-inline-block"
              />
            </span>
            <span>Click me! opened: {{ open }}</span>
          </template>
        </v-expansion-panel-header>
        <v-expansion-panel-content>
          <template v-if="loadTextfields">
            <v-text-field v-for="(item, i) in 1500" :key="i"/>
          </template>
        </v-expansion-panel-content>
      </v-expansion-panel>
    </v-expansion-panels>
  </template>
</v-app>

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

Conceal certain digits of a credit card number in a masked format for security purposes

Is there a reliable method to mask Credit Card numbers in password format within a text field? **** **** **** 1234 If you are aware of a definitive solution, please share it with us. ...

Kurento's WebRTC feature is currently experiencing difficulties with recording functionality

Currently, I am attempting to capture video using the Kurento Media Server with nodejs. Following the hello-world example provided here, I connected a recorderEndpoint to the webrtcEndpoint and successfully got everything up and running. However, on the se ...

JQuery functions are functioning properly in Internet Explorer 10, but are encountering issues in Internet Explorer

My JavaScript function calls a jQuery function that works in IE10 but not in IE7. function test() { // Display message before calling jQuery function... alert("Before"); // Call the jQuery function... $("#boxscroll").getNiceScroll().resize(); // Display m ...

The equation of jquery plus ie7 results in an undefined value

I am experiencing a strange issue in IE7 with a jQuery script. This problem seems to only occur in IE7. In summary, when I check the console window, it shows that jQuery is not defined - even though I have loaded jQuery (version 1.7.1) from my disk and can ...

Showing JSON data in AngularJS

I need help with AngularJS to display JSON output. Is using gridOptions the best approach for this? I'm trying to print labels starting from the root in reverse order - label/parent's label/parent's parent's label/... { artifac ...

Encountering a 404 error while using the Post method with Axios in a ReactJS

I am experiencing an issue with axios.js. I am attempting to use the POST method, but it is resulting in a 404 error and I am unsure how to resolve it. The error message is as follows: > POST http://localhost:3000/api/match 404 (Not Found) > createE ...

What are the steps to customize the format of Vue3 Datepicker extensions?

Is there anyone who can lend a hand? I am currently using the Vue3 Datepicker and I have received a value that looks like this Thu Jun 23 2022 17:14:00 GMT+0700 (Western Indonesia Time) Does anyone know how to transform it into the following format? Thu, ...

Mastering the art of resolving a dynamic collection of promises with '$.all'

Imagine having 3 promises and passing them to $q.all. This results in a new promise that resolves when the 3 promises are resolved. But what if I realize before the 3 promises resolve that I also want a 4th promise to be resolved? Can this be achieved? I ...

Using JWT for authentication in Vue.js

Currently, I am developing a single-page application using Vue.js and vue-router. My focus is on implementing authorization/authentication using JWT. The backend (API endpoint) has been configured to issue a token upon login and verify the required header ...

Customize the URL path in Next.JS according to the user's location

My Next JS website is hosted on the domain abc.com. I would like the site to automatically detect a visitor's location, retrieve their country code, and then redirect them to abc.com/country_code. ...

What is the best way to retrieve the IDs of selected items in jQuery selectables?

I have a straightforward question that I've been struggling to find an answer to. When using jQuery selectables, I want to retrieve the ID of the selected list item when it's clicked. Here is an example of my list: <ol id="selectable"> ...

What is the best way to trigger a modal on Bootstrap using a JavaScript/jQuery function?

I encountered an issue while attempting to call a bootstrap modal using a simple button or link, which may be due to a conflict with my select2 plugin (although I am uncertain). I tried appending the button to the select2 dropdown but it doesn't seem ...

What steps can I take to improve this code and prevent the error "Property 'patient' does not exist on type 'Request<ParamsDictionary>'" from occurring?

I'm having some issues with my code. I am attempting to use passport authenticate in order to save patient information that is specific to the token generated for each individual. router.get("/current", passport.authenticate("jwt", { session: false }) ...

What is the best way to disengage a loop of elements within an internship?

In my scenario, the DOM structure is as follows: <table id="campaigns"> <tr> <th>Name</th> <th>Status</th> </tr> <tr> <td>first data</td> </tr> <tr data- ...

Executing Javascript to populate a div element with content based on its CSS class

Is there a way to isolate my View (HTML & CSS files) within a controller like JavascriptCode/AJAX, so that upon page load, only the controller binds the data to a specific element such as a DIV based on its class? Do you think this is achievable? If so, ...

Bidirectional communication between two AngularJS scopes or controllers utilizing a service

I am facing numerous situations where I require clicks or other interactions to trigger actions in a different area of the webpage (one-way communication). Now, I have encountered a need for bidirectional communication, where changes made in element A can ...

Start the Vuepress build process and run the generated project

I have created a basic Vuepress project with PWA support. Currently, Vuepress only offers two scripts: "scripts": { "docs:dev": "vuepress dev docs", "docs:build": "vuepress build docs" } The de ...

Delay the v-alert display after an item is added to the array basket using setTimeout

here is my custom rightTableMenu template <template> <div> <h1 align="center">{{ title }}</h1> <v-alert type="info" icon="mdi-emoticon-sad" v-if="basketStatus"> Empty Basket, please add some to basket < ...

Using Javascript to open a PDF in a new tab directly from a byte array

I am currently using AngularJS along with an HTTP resource to make a request to an external API. The response I am getting back is in the form of a byte array. My goal is to convert this byte array into a PDF and open it in a new window. So far, I have not ...

Transmit the JavaScript array via AJAX to PHP server

Is it possible to transfer a JS array created using the .push function to another PHP file? I have included the code snippets for the two files involved, game.js and gallery.php. In Game.js: imgarray.push({"img_name": img_name,"x": x_value,"y": y_value,"w ...