Tips for postponing 'not found' error until the data has finished loading in Vue.js

I am accessing the following route: http://site.dev/person/1

The structure of my component is as follows:

// PeopleComponent.vue

<template>

<div>
   <template v-if="person == null">
       <b>Error, person does not exist.</b>
   </template>

   <template v-else>
       <pre> {{ person }} </pre>
   </template>
</div>

</template>

<script>
export default {


    mounted() {
      this.$store.dispatch('getPeople');
    }

    computed: {

      // represents the person whose id potentially matches the value of `/:id` in route.
      person(){ 
          let id = parseInt(this.$route.params.id)
          let person = null

          if(id > 0)
              person = this.$store.state.people.find(p => p.id == id)

          return person;
      }

    }



}
</script>

// [styles]

Explanation of Component Functionality:

A unique ID is provided in the URL. This ID corresponds to a specific item displayed on the page. A computed property named person() retrieves the object from the Vuex store based on the ID parameter in the URL.

Intended Outcome:

Initially, I want to display an error message at the top of the page if the requested object cannot be found. If the object exists, a simple representation of it should be displayed. The current functionality works, but there is a slight delay between fetching data from the API and locating the correct object in the store. This delay causes the error message to briefly appear, especially on slower network speeds. I aim to eliminate this display so that the error message does not show up at all when the object exists.

Troubleshooting Attempts:

  • v-cloak - Applied to various parent divs including div#app with no success.
  • v-if - Utilized as shown in the example above.

Any guidance on resolving this issue would be greatly appreciated. Thank you!


Update 31/03/2020

In line with Phil's suggestion, I tried incorporating a flag to indicate page readiness through two methods.

Method #1 Modified mounted() to 'async' and added an await statement for the action retrieving people from the API, setting the flag to true afterward:

async mounted() { 

  await this.$store.dispatch('getPeople');
  this.loaded = true;

}

Still seeing the error message momentarily.

Method #2

Employed a then callback within the action, setting the flag to true inside the callback function:

mounted() {

  let vm = this

  vm.$store.dispatch('getPeople').then(() => {

      vm.loaded = true;

  })

}

Both approaches failed to prevent the error message from appearing initially.

Suspected Issue:

Main Principle

Error should ONLY show if loaded=true and person=null

  1. Page loads with loaded=false and person=null. Error doesn't display.
  2. API call fetches people data without displaying the error.
  3. After the call, loaded changes to true. [At this point, loaded=true, and the computed person hasn't resolved yet, causing the momentary error display.]
  4. Computed property finds the relevant record in the store shortly after.
  5. Error vanishes once person is retrieved and is no longer null.

Edit 01/04/2020

Responding to Phil's inquiry:

What does your getPeople() action look like?


getPeople({ commit })  {   
        axios.get('/get/people')
        .then(response => {
            commit("getPeople", response.data);
        })
        .catch(error => {
            console.log(error);
        })
},

Answer №1

It appears that adding one more piece of state, such as loading, could be beneficial.

To make your getPeople action composable, consider modifying it to return the Axios Promise to ensure it waits for the async task to complete...

getPeople ({ commit })  {
  // Ensure you return the promise
  return axios.get('/get/people').then(response => {
    commit("getPeople", response.data)
  }).catch(error => {
    console.error(error)
    // Make sure not to accidentally convert this to a successful response
    return Promise.reject(error)
  })
},

Then, consider implementing something like this:

export default {
  data: () => ({ loading: true }),
  async created () {
    // "Created" triggers before "mounted"
    await this.$store.dispatch('getPeople')
    this.loading = false
  },
  computed: {
    // Additional code here
  }
}

You can now utilize loading in your template:

<div v-if="loading">Loading...</div>
<div v-else>
  <!-- Include your "person" template content here -->
</div>

Answer №2

Important Update

While I initially thought my method was sufficient, after reviewing Phil's response, I realized his explanation of the issue was clearer and offered a more effective solution. Now, instead of relying on a timer for my loader, I am waiting for the Promise to be fulfilled.

Upon reflection, I understood that I was essentially asking the system to wait indefinitely until the information was accessed. During this waiting period, something needed to be displayed. This led me to question, "What should appear in that space before the data arrives?" Since instant loading is not possible, I decided to include a spinner animation.

The challenge arose from the uncertainty surrounding how long the spinner should be present. To address this, I established a global variable named timeout.

My revised approach now involves:

1) Displaying the loader if the timeout has not elapsed and the resource is still empty

2) Revealing the loaded resource once it is accessible

3) Showing an error message if the resource remains empty after the timeout period expires

I am satisfied with these adjustments as they provide a more efficient solution to the problem.

Answer №3

I encountered a similar issue and found a solution by using Vue-progressbar. You can access it through this link:

I successfully integrated it into my project, so if you need any assistance, feel free to reach out to me.

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

Phonegap - Retaining text data in a checklist app beyond app shutdown

This is my first time developing an app with Phonegap. I am looking to create a checklist feature where users can input items into an input field. However, I am struggling with figuring out how to save these items so that they remain in the checklist even ...

Is it possible to transfer a value when navigating to the next component using this.props.history.push("/next Component")?

Is there a way I can pass the Task_id to the ShowRecommendation.js component? recommend = Task_id => { this.props.history.push("/ShowRecommendation"); }; Any suggestions on how to achieve this? ...

Customize the text displayed for the number of rows per page in the footer of a v-data-table in Vuetify

Currently, I am using v-data-tables in Vuetify and.... I'm looking to modify the following text: https://i.stack.imgur.com/LZSrg.png Although I tried adding this code, it doesn't seem to be functioning properly: https://i.stack.imgur.com/EG1C ...

Extracting the id of an element using jQuery

The desired outcome is for the code to print the id of the selected div, but it's not working as expected. I've reviewed it multiple times but couldn't pinpoint the error. Any assistance would be greatly appreciated. Here is the HTML: < ...

Navigating through the content of slots within recurring slots in a subcomponent in Vue.js

I am encountering an issue with a child component, where each row in an object is rendered inside a div with a specific slot. I need to pass data from the parent for each of these elements. I've been attempting to iterate through every element of the ...

Error: `$(...).fullCalendar is not a function` when using React

After scouring through multiple posts discussing similar issues, I've noticed a common theme of problems arising from improperly loading jQuery or fullcalendar. However, in my case, I have both components loaded into my code (although I can't be ...

Can security groups be dynamically updated using a JSON file in JavaScript rather than relying on manual parameters?

Looking to enhance security group rules, I aim to have my javascript file extract data from a separate json file instead of relying on json parameters directly. After initially using json parameters for security group updates, I am now exploring the metho ...

ReactJS encountered an error: _this3.onDismissID is not defined as a function

My goal is to retrieve the latest news related to a specific search term from a website, showcase them, and provide a dismiss button next to each news item for users to easily remove them if desired. Here's a snippet of the code I'm using: import ...

What is the best way to remove multiple IDs from req.params using Sequelize?

Is there a way to handle req.params that contain multiple IDs? I need to search for and delete these multiple IDs. Here is the code snippet: const ids = req.params; const masterFunders = await masterFunder.findOne({ where: { id: ids ...

converting time stamps to written text

Is there a JavaScript library available that can convert a timestamp (Date Java class value) to text? For example: Just two minutes ago 4 hours back 23 August 2009 Does such a library exist? If not, I'll take on the challenge of implementing it ...

Issues with voice state updates in JavaScript

I am currently working on setting up a discord bot to send notifications when someone joins a voice chat. While coding in Atom, I encountered the following error: TypeError: Cannot read property 'send' of undefined at Client.client.on (C:\U ...

Issue with Braintree drop-in form: Nonce string generation problem

I've encountered a peculiar issue while trying to utilize the dropin form from Braintree. Successfully integrating the form into a view, here's how it looks: <form id="createTransactionForm" method="post" action="#&qu ...

Attempt to generate a function in JavaScript that mirrors an existing one

How can I create a javascript function similar to loadAllOriginal, but with the value of the variable allEmployees being a list of employee objects (ID, FirstName, LastName)? I am attempting to implement this method in combination with autocomplete from ...

Tips on emulating typing actions in an input field during a Jest test

I am working on a component that displays type-ahead suggestions as the user types in a text field. The suggestions are fetched from a server based on the input provided by the user. I want to test this functionality by simulating a scenario where the us ...

Is there a more efficient method to choose specific UV coordinates from a texture for presentation on a sprite using three.js?

I've got a texture sheet that contains various game HUD elements UV packed together in one texture. Currently, I find myself having to create a clone() of the texture for each individual part of the GUI, then create a material using this texture in o ...

Having trouble utilizing vue-bootstrap's $bvModal feature in Vuejs for dynamic modal rendering

Is there a way to dynamically render modal of vue-bootstrap without writing any HTML code? I encountered an error when trying to utilize bvModal.msgBoxOk('sad') in my Vue project after referring to the documentation at BootstrapVue Modal Message ...

Vuetify 2.0: Enhancing Slot Headers

Hello there! I've been working on customizing the slot header for a data table using vuetify.js to incorporate tooltips, which is all going smoothly. However, I'm facing an issue where the arrows for ascending and descending order are not appeari ...

Encountered an issue loading resource: net::ERR_BLOCKED_BY_CLIENT while attempting to access NuxtJS API

After deploying my NuxtJS 2 app on Vercel and adding serverMiddleware to include an api folder in the nuxt.config.js file, everything was working smoothly. However, when I tried making an api call on my preview environment, I encountered an error: POST htt ...

Unable to locate "Gruntfile.js" Node module for task execution

I am currently in the process of developing a module that enables node to execute Grunt tasks via the command line. This Node module is globally installed at : C:\Users\pcharpin\AppData\Roaming\npm\node_modules\task-app ...

What is the method to rotate an SVG icon contained within a button when clicked?

I'm attempting to incorporate a CSS animation into an SVG that is enclosed within a button. Example <button class="spin"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ari ...