After changing the value of a <select> element in Vue, the fetched data is delayed by one step

I'm currently working on a feature that involves fetching data from a URL that changes every time a user chooses a new value from a <select> dropdown. The fetched data updates the songkickData array with the latest information. However, when I check the songkickData array using console.log after each <select> change, it displays data from the previous selection instead of the current one.

I suspect that the issue lies in the timing of when the code is executed, synchronicity, or possibly promises, but I haven't fully grasped these concepts yet.

Below is the code snippet:

<template>
  <select v-model="selected" @change="getCityData">
    <option v-for="city in cities" :key="city.id" :value="city.id">{{ city.label }}</option>
  </select>
</template>

import cityData from "../data/songkickCityData.js"

export default {
  data() {
    return {
      cities: cityData,
      songkickData: []
    }
  },
  methods: {
    getCityData(e) {

      const songkickCityId = e.target.value

      let songkickUrl = this.getSongkickUrl(songkickCityId)      

      fetch(songkickUrl)
        .then(res => res.json())
        
        .then(data => this.songkickData = data)
      
      this.getRandomGig()
      
    },
    getSongkickUrl(songkickCityId) {
      const now = new Date()
      const today = now.toISOString().slice(0, 10)
      const songkickAPIKey = 'XXXXXXXXXXXXX'
      let songkickUrl = `https://api.songkick.com/api/3.0/metro_areas/${songkickCityId}/calendar.json?min_date=${today}&apikey=${songkickAPIKey}`;

      return songkickUrl
    },
    getRandomGig() {
      
      // I need to ensure that the data fetched is based on the current select value and not the previous one.
      console.log(this.songkickData)

    }
  }
}

Answer №1

Instead of using then(), try utilizing async/await in your code. With async/await, the execution pauses until the promise is resolved, unlike with then() where the code continues to run and returns to execute callback functions.

Due to this behavior, your console.log() may run before the fetch is resolved, leading to outdated values being used in subsequent calls to getCityData(). To resolve this issue, consider making the switch to async/await for a more synchronized approach.

For more information, you can refer to this article.

In order to address this problem, you can update your code as follows:

<template>
  <select v-model="selected" @change="getCityData">
    <option v-for="city in cities" :key="city.id" :value="city.id">{{ city.label }}</option>
  </select>
</template>

import cityData from "../data/songkickCityData.js"

export default {
  data() {
    return {
      cities: cityData,
      songkickData: []
    }
  },
  methods: {
    async getCityData(e) {

      const songkickCityId = e.target.value

      let songkickUrl = this.getSongkickUrl(songkickCityId)

      let res = await fetch(songkickUrl)
      let data = await res.json()
      
      this.songkickData = data
      this.getRandomGig()
      
    },
    getSongkickUrl(songkickCityId) {
      const now = new Date()
      const today = now.toISOString().slice(0, 10)
      const songkickAPIKey = 'XXXXXXXXXXXXX'
      let songkickUrl = `https://api.songkick.com/api/3.0/metro_areas/${songkickCityId}/calendar.json?min_date=${today}&apikey=${songkickAPIKey}`;

      return songkickUrl
    },
    getRandomGig() {
      
      // Access the data based on the current selection value here
      console.log(this.songkickData)

    }
  }
}

You can also opt to transition to using async/await for improved code readability and synchronization.

Answer №2

The Fetch API is a useful asynchronous web tool. By default, a fetch() request will time out at the specified browser setting. This means that the this.getRandomGig() method will be called before the fetch() request is resolved or rejected.

If you want to ensure that this.getRandomGig() is only called after the fetch() request has completed successfully, you can place it inside the promise returned by fetch(). Here's an example:

fetch(songkickUrl)
    .then(res => res.json())
    .then(data => { this.songkickData = data; this.getRandomGig(); })

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

Tips for dynamically updating an HTML value with Javascript

Summary of My Issue: This involves PHP, JS, Smarty, and HTML <form name="todaydeal" method="post"> <span id="fix_addonval"></span> <input type="radio" name="offer" id="offer_{$smarty.section.mem.index+1}" value="{$display_offe ...

Avoiding the "urls" format using the onBeforeRequest function

chrome.webRequest.onBeforeRequest.addListener(function(details) { if (localStorage.on == '1') { return {cancel:true}; } }, {urls: ["*://*.domain1.net/*","*://*.domain2.com/*","*://*.domain3.com/*"], types: ["script","xmlhttpreques ...

Showing a series of JavaScript countdowns consecutively

I am working on a project where I want to display a second countdown after the first one finishes using meteor. The initial timer code looks like this: sec = 5 @timer = setInterval((-> $('#timer').text sec-- if sec == -1 $('#time ...

Value as a String inside an Object

I am encountering an issue with using the obj to store string values in my project. The strings contain commas, and for some reason, it is not working as expected. const resizedUrl ={ 'mobile': "'images','400x/images' ...

Create a left-aligned div that spans the entire width of the screen, adjusting its width based on the screen size and positioning it slightly

I have a parent container with two child elements inside. I want the first child to align to the left side and the second child to align to the right side, but not starting from the exact center point. They should be positioned slightly off-center by -100p ...

Maximizing Efficiency on the Frontend: Balancing Requests with Caching

I am currently tackling a large website that has accumulated quite a bit of technical debt that needs to be addressed. The site contains a significant amount of JavaScript and CSS files being loaded. Currently, these files are aggregated and minified in la ...

Crafting an integrated REST API model with interconnected data

This question revolves around the implementation of a specific scenario rather than a problem I am facing. Let's say we have a User and a Resource, where a User can have multiple Resource but a Resource can have only 1 User. How should API endpoints b ...

Navigating to the next page in Angular JS by clicking "Save and Next" which

Hey there, I'm currently diving into Angular JS and working on a CMS system with it. Right now, we're dealing with around 30 to 40 Objects that we load into a list. Whenever one of these objects is clicked, a Modal Window pops up using the Modal ...

Locate the highest and lowest values within a .json file

When working on a graph using d3.js, one key step is setting up the scales for the axis. The data for the graph is stored in a Json file with multiple arrays, each representing different regions and years: [{ "id" : "AustraliaNewZealand" , "year" ...

How can a TypeScript Angular directive utilize a function?

Recently, I have been following a unique Angular directive TypeScript pattern that I find really effective. The approach involves giving the directive its own isolated scope by creating a new controller. I encountered a scenario where I needed to invoke a ...

How should one go about creating an npm package out of a vuejs component and testing it locally?

Initially, I created a vuejs project as a test container using vue-cli. Next, I developed an npm package named "vue-npm-example" from a Vuejs component in my local environment and then imported it into the aforementioned testing project. Within the packag ...

Trail of crumbs leading to pages displayed in a div container

My website is designed with only one page where all other pages are loaded within a div. I am looking to implement breadcrumbs to keep track of the pages loaded inside the div. However, the solutions I have found online only work for pages loaded in the en ...

What is the best way to use jQuery to toggle the visibility of a <panel>?

My objective is to display a panel with two labels on a button click, but I'm facing issues achieving this functionality. When I click on the button (id=Button1), the panel (id=anspanel) should appear, but it remains hidden even after clicking the but ...

Importing a file using its absolute path in JavaScript

Within the dependencies directory, there exists a module named foo: import foo from '../dependencies/foo'; // This import statement works as intended The challenge arises when attempting to import from a different path due to deployment in an AW ...

Is it possible to use a pass-through or helper function to invoke Asynchronous Generators in Node.js?

Exploring New Territory Upon my discovery that the asynchronous generator pattern is relatively novel in JavaScript and currently only supported in Node.js starting from version 10, I delved deeper into its functionalities. Now, equipped with this knowled ...

How can componentsProps be utilized within Material-UI components?

While going through the API documentation of components like AutoComplete, StepLabel, and BackDrop, I came across the componentsProps property. However, I haven't found a clear explanation or example of how to use this prop effectively. If anyone cou ...

What is the best way to turn off the annoying pop-up messages that show up for input validation, specifically the one that says "Please complete

Currently using Angular 2, my form has input fields similar to this simplified version: <input class="body-text1" type="text" [(ngModel)]="model.name" name="name" required minlength="1"> <!--more inputs like this --> Although I have implement ...

Calculating the combined total and mean values within an object using JavaScript

I have a set of data in the following format: { "Dates": ["January", "January", "March", "March", "March", "November", "November"], "Values": [45.6, 0.5, 59.3, 46.56, ...

The standard process and organization of a project using AngularJS in conjunction with Python Flask

As someone new to the MV* client-side framework craze, I find myself leaning towards AngularJS over Knockout, Ember, or Backbone. However, I'm unsure about the workflow involved. Should I start by developing a client-side application in AngularJS and ...

How to invoke a function from a different ng-app in AngularJS

I have 2 ng-app block on the same page. One is for listing items and the other one is for inserting them. I am trying to call the listing function after I finish inserting, but so far I haven't been successful in doing so. I have researched how to cal ...