4
votes

So I'm populating the data table with items fetched via API and it is working fine, but if I want to edit any of the fields it's not quite working out.

The item only updates if I manually do something like search or sort. (inside the data table)

The fields I'm trying to modify are item.tuning and item.url via getTab()

<v-data-table 
class="tableElem"
:headers="headers"
:items="playlist"
:loading="loadingPlaylist"
:search="search"
:pagination.sync="pagination"
:rows-per-page-items="[15]"
hide-actions
>
<v-progress-linear slot="progress" color="purple" indeterminate></v-progress-linear>
<template slot="items" slot-scope="props">
  <td>{{ props.item.artist }}</td>
  <td class="text-xs-right">{{ props.item.track }}</td>
  <td class="text-xs-right">{{ props.item.tuning | tuning }}</td>
  <td class="text-xs-right">
    <v-btn 
    v-if="props.item.url" 
    depressed outline light 
    style="margin-top:1rem;margin-bottom:1rem;" 
    :href="props.item.url" 
    target="!blank">
      Tab
    </v-btn>
    <div class="text-xs-center" v-else-if="props.item.url == false">No tab :(</div>
    <v-btn 
    v-else 
    depressed outline light 
    style="margin-top:1rem;margin-bottom:1rem;" 
    v-on:click="getTab(props.item.artist, props.item.track, props.item)">
      Get Tab
    </v-btn>
  </td>
</template>
<v-alert slot="no-results" :value="true" style="color:black;" icon="warning">
  Your search for "{{ search }}" found no results.
</v-alert>
</v-data-table>

methods:

getTab(artist, track, item) {
  //const tabURL = "https://stark-beyond-77127.herokuapp.com/spotify/gettab";
  let itemIndex = this.playlist.indexOf(item)
  const tabURL = "http://localhost:5000/spotify/gettab";
  const tabJSON = {
    artist: artist,
    track: track
  };
  axios.post(tabURL, tabJSON).then(response => {
    let tuning = response.data[0].tuning;
    let url = response.data[0].url;
    this.playlist[itemIndex] = { ...this.playlist[itemIndex], ...{ tuning: tuning, url: url } };
    console.log(this.playlist[itemIndex]);
  });
}

My guess here is that I'd have to use computed: or watch: but dont know how to implement that. Thanks

5
how are you trying to modify those fields? via an edit button or in-line edit?Jaya
@Jaya there's a button Get Tab that fires function getTab that inserts the result got from API to correct index in array if that makes any sense. So then there's v-if for different kind of results if(props.item.url)else if(props.item.url == false) and else. So what i'm looking for basically is for the text to update accordingly after the function is donebreke

5 Answers

14
votes
let itemIndex = this.playlist.indexOf(item)
let editedItem = { ...this.playlist[itemIndex], ...{ tuning: tuning, url: url } };
this.playlist.splice(itemIndex, 1, editedItem)

Fixes the problem. I'd guess splice forces a dom refresh that directly editing array didn't.

1
votes

If anyone facing this problem too, I would like to share my solution.

The solution is declare the attribute to null before adding new attribute to JSON array.

In OP case,

const tabJSON = {
    artist: artist,
    track: track
    tuning: null,
    url: null
};

This is my problem, the added attribute to array of json object does not show unless sort button is clicked.

problem gif

In my case, I need to retrieve data from firestore and add in attributes into array.

db.collection("checkout")
  .get()
  .then(querySnapshot => {
    querySnapshot.forEach(doc => {
      const data = {

        book_did: doc.data().book_did,
        borrowed_date: doc.data().borrowed_date.toDate(),
        due_date: doc.data().due_date.toDate(),

        book_title: null, // solution
        returned_date: null, // solution
        days_late: null // solution
      };
      this.checkout.push(data);
    });

    // modified this.checkout array here:
    Object.keys(this.checkout).forEach(key => {
      db.collection("books")
        .doc(this.checkout[key].book_did)
        .get()
        .then(snapshot => {
          this.checkout[key].book_title = snapshot.data().title;
        });
    });
  });
1
votes

Vue cannot pick up the change in array when you directly set the index or changing the length.

See article: Update Array and Object in Vuejs.

Instead you can use:

Vue.set(vm.items, indexOfItem, newValue)

vm.items.splice(indexOfItem, 1, newValue)

0
votes

In my case, unexpected behaviour comes from the v-for key. My data are not using "id" as the key. After I re-read the docs, I realized that Vuetify is using "id" as the default key for the items.

The solution is I have to specify the item-key props for the v-data-table so that it behaves as expected.

Example:

data: () => ({
  playlist: [
    { key: 1, name: 'Foo' },
    { key: 2, name: 'Bar' },
  ],
}),

Use item-key:

<v-data-table :headers="headers" :items="playlist" item-key="key">
0
votes

I think this in closure callback is not this which contain your arrays. So I have a trick to solve your problem is set variable for this

getTab(artist, track, item) {
  //const tabURL = "https://stark-beyond-77127.herokuapp.com/spotify/gettab";
  let itemIndex = this.playlist.indexOf(item)
  const tabURL = "http://localhost:5000/spotify/gettab";
  const tabJSON = {
    artist: artist,
    track: track
  };
const _this = this
  axios.post(tabURL, tabJSON).then(response => {
    let tuning = response.data[0].tuning;
    let url = response.data[0].url;
    _this.playlist[itemIndex] = { ...this.playlist[itemIndex], ...{ tuning: tuning, url: url } };
    console.log(this.playlist[itemIndex]);
  });
}