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 creating a fixed element with ScrollTrigger and GSAP

How can I prevent the right div from jumping on top of the left div when using a scroll trigger to make the left div's position fixed? gsap.registerPlugin(ScrollTrigger); const tlfour = gsap.timeline({ scrollTrigger: { trigger: ".ma ...

Encountering an Unhandled Exception with Laravel Sanctum and Vuex when Implementing Vue Router Navigation Guard

Looking for some advice on my current situation. I have a Laravel application with a Vue front-end, and I am using Laravel Sanctum to connect to the API within the same app. My goal is to configure authentication guards so that routes can only be accessed ...

Create a toggle effect using attribute selectors in CSS and JavaScript

I am looking to switch the "fill: #000;" from the CSS property "svg [id^='_']". Usually, I would use a method like this, but it seems that I can't do so because "svg [id^='_']" is not an element, correct? pub.toggleClass = functi ...

Creating a dynamic tbody element on button click with the help of javascript or jquery

I am working with the following code: $(document).ready(function() { //Optimizing by selecting tbody first using jquery children var tbody = $('#myTable').children('tbody'); //If no tbody found, select the table itself ...

When using Angular 2, the array.splice() function is causing the elements to be removed from the

I am currently working with an HTML table that has default checked rows. <table> <tr> <th></th> <th>Id</th> <th>Name</th> <th>Initial</th> </tr> ...

Is it allowed to use an ID as a variable identifier?

One method I often use is assigning a variable with the same name as the id of an element, like this: randomDiv = document.getElementById("randomDiv"); randomDiv.onclick = function(){ /* Do something here; */ } randomDiv.property = "value"; This tech ...

Make sure to validate onsubmit and submit the form using ajax - it's crucial

Seeking assistance for validating a form and sending it with AJAX. Validation without the use of ''onsubmit="return validateForm(this);"'' is not functioning properly. However, when the form is correct, it still sends the form (page r ...

Leverage JavaScript to retrieve the formatting of an element from an external CSS stylesheet

Check out this HTML snippet: <html> <head> <link rel="stylesheet" type="text/css" media="all" href="style.css"> </head> <body> <div id="test">Testing</div> <script> ...

fnRedraw and fnReloadAjax do not have the capability to refresh the datatable

I have been working on updating a table with new data from an ajax url. The table loads correctly the first time, but I am struggling to get it to refresh. $(function() { var datepicker = $( "#date-picker" ); var table = $("#reports1").dataTable( ...

How to apply an icon image using the background property in CSS in Vue 3

Need help setting background image from the public folder |_public | |_images | |_icon.png |_src |_components |_TheHeader.vue I'm having difficulty trying to set an image as a background in TheHeader.vue using CSS, but the image is located in ...

Display or conceal elements by utilizing ng-show/ng-hide according to specific conditions

Here is the code snippet I am working with: <input class="form-field form-control" type="text" name="Website" ng-model="vm.infodata.Website" placeholder="Website Address" maxlength="50" required ng-pattern="/^(www\.)?[a-zA-Z0-9_&bs ...

Mixing strings with missing slashes in links

console.log(mylink) When using the console to log mylink, the expected result is a normal link like http://example.com/something.jpg. I tried concatenating it as shown below: var html = '<div id="head" style="background:linear-gradient(rgba(0, 0 ...

Make sure to update the package.json file at multiple locations following the execution of the "npm i" command

My goal is to automatically detect any newly installed packages based on my package.json file. This way, whenever I run "npm i", the new package will be added not only to the usual "dependencies" section but also to a custom section called "extDependenci ...

Draggable slider not functioning properly with linear interpolation

Recently, I've been delving into the world of "linear interpolation" and its application in creating easing effects. However, while the easing functionality of the draggable slider seems to be operational, I'm encountering an issue. The slider re ...

Connect the v-model to a non-existent property (Array) in Vue JS

I am struggling with retrieving questions from the database and displaying them along with options on a webpage. Here is an example: <div v-for="(question,index) in questions"> <div class="interview__item-text ...

Seeking advice on removing the initial blank space from a dropdown value in Angular.js

I have a deeply thought-out logic that I would like to illustrate with an example. However, in order to present it effectively, I am looking for suggestions on how to simplify the process without relying too heavily on the controller. <select class="fo ...

Creating various containers in React JS for different components

I am faced with the task of rendering multiple DOM elements from my JavaScript code. Imagine I have div elements like this: <div id="div1"><div> //Some Html tags <div id="div2"><div> //Some Html tags <div id="div3" ...

Issue with data entry: unable to enter the letter 'S' in search field

This bug has been a real challenge for me. It's strange, but I'm unable to type the letter "S" into the search input field. Oddly enough, the keyboard seems to be functioning properly. Please find the sandbox below for reference: https://codes ...

Display a div every 3 seconds with the help of jQuery

I am seeking a solution to display the second div (box2) every 3 seconds. Can anyone help me achieve this using jQuery? <div id="box1" style="background-color:#0000FF"> <h3>This is a heading in a div element</h3> <p>This ...

Using Gmail in conjunction with Heroku for email delivery

After completing an order in my web app, I want to automatically send a confirmation email. I decided to use Nodemailer as it is a popular npm package for this purpose. I successfully coded the functionality and tested it in my local environment. Howeve ...