1
votes

I have a simple vuetify datatable that performs CRUD operations. I am using axios and a mongo database. When I add a new item, the information is correctly displayed in the client side and posted in the mongo database. However, I cannot access to updated information of the mongo database, particularly the id that mongo created, unless I reload the webpage. I am newcomer in Vue, please be patient. A simplified version of the problem:

 axios
   .post('http://localhost:5000/dessert', {
   name: this.editedItem.name
 })

 console.log(this.editedItem.name) // I CAN ACCES WITHOUT PROBLEM
 console.log(this.editedItem._id) // I NEED TO RELOAD THE WEBPAGE IN ORDER TO ACCES THIS ELEMENT. THE ID THAT MONGO CREATED.

Vue file:

<template>
  <v-data-table
    :headers="headers"
    :items="desserts"
    sort-by="calories"
    class="elevation-1"
  >
    <template v-slot:top>
      <v-toolbar flat color="white">
        <v-toolbar-title>My CRUD</v-toolbar-title>
        <v-divider
          class="mx-4"
          inset
          vertical
        ></v-divider>
        <v-spacer></v-spacer>
        <v-dialog v-model="dialog" max-width="500px">
          <template v-slot:activator="{ on }">
            <v-btn color="primary" dark class="mb-2" v-on="on">New Item</v-btn>
          </template>
          <v-card>
            <v-card-title>
              <span class="headline">{{ formTitle }}</span>
            </v-card-title>

            <v-card-text>
              <v-container>
                <v-row>
                  <v-col cols="12" sm="6" md="4">
                    <v-text-field v-model="editedItem.name" label="Dessert name"></v-text-field>
                  </v-col>
                  <v-col cols="12" sm="6" md="4">
                    <v-text-field v-model="editedItem.calories" label="Calories"></v-text-field>
                  </v-col>
                </v-row>
              </v-container>
            </v-card-text>

            <v-card-actions>
              <v-spacer></v-spacer>
              <v-btn color="blue darken-1" text @click="close">Cancel</v-btn>
              <v-btn color="blue darken-1" text @click="save">Save</v-btn>
            </v-card-actions>

          </v-card>
        </v-dialog>
      </v-toolbar>
    </template>

    <template v-slot:item.action="{ item }">
      <v-icon
        small
        class="mr-2"
        @click="editItem(item)"
      >
        edit
      </v-icon>
      <v-icon
        small
        @click="deleteItem(item)"
      >
        delete
      </v-icon>
    </template>

    <template v-slot:no-data>
      <v-btn color="primary" @click="initialize">Reset</v-btn>
    </template>
  </v-data-table>
</template>

<script>
import axios from 'axios'

  export default {
    data: () => ({
      dialog: false,
      headers: [
        {
          text: 'Dessert (100g serving)',
          value: 'name',
        },
        { text: 'Calories', value: 'calories' },
        { text: 'Actions', value: 'action', sortable: false },
      ],
      desserts: [],
      editedIndex: -1,
      editedItem: {
        name: '',
        calories: 0,
      },
      defaultItem: {
        name: '',
        calories: 0,
      },
    }),
    mounted() {
       this.fetchItems()
    },

    computed: {
      formTitle () {
        return this.editedIndex === -1 ? 'New Item' : 'Edit Item'
      },
    },
    watch: {
      dialog (val) {
        val || this.close()
      },
    },
    created () {
      this.initialize()
    },

    methods: {
      fetchItems(){
      axios
        .get('http://localhost:5000/dessert')
        .then(response => (this.desserts = response.data.data))
        },

      editItem (item) {
        this.editedIndex = this.desserts.indexOf(item)
        this.editedItem = Object.assign({}, item)
        this.editedID = this.editedItem._id
        this.name = this.editedItem.name
        this.calories = this.editedItem.calories
        this.dialog = true
      },

      deleteItem (item) {
        const index = this.desserts.indexOf(item)
        this.deletedItem = Object.assign({}, item)
        console.log(this.deletedItem)
        this.deletedID = this.deletedItem._id
        console.log(this.deletedID)
        if (confirm("Do you really want to delete?")) {
          axios.delete(`http://localhost:5000/dessert/${this.deletedID}`);
          this.desserts.splice(index, 1);
        }
      },

      close () {
        this.dialog = false
        setTimeout(() => {
          this.editedItem = Object.assign({}, this.defaultItem)
          this.editedIndex = -1
        }, 300)
      },
      save () { // Edit Item
        if (this.editedIndex > -1) {
          Object.assign(this.desserts[this.editedIndex], this.editedItem)
          axios.delete(`http://localhost:5000/dessert/${this.editedItem._id}`)
          axios
            .post('http://localhost:5000/dessert', {
            name: this.editedItem.name,
            calories: this.editedItem.calories
            })

          // New Item
        } else {
          this.desserts.push(this.editedItem)

          axios.post('http://localhost:5000/dessert', {
          name: this.editedItem.name,
          calories: this.editedItem.calories
          })
        }

        this.close()
      },
    },
  }
</script>

Python file:

from flask import Flask
from flask import jsonify
from flask import request
from flask_pymongo import PyMongo
from flask_cors import CORS
from bson.objectid import ObjectId

app = Flask(__name__)
#CORS(app)

# instantiate 
app.config.from_object(__name__)

# enable CORS
CORS(app, resources={r'/*': {'origins': '*'}})

app.config['MONGO_DBNAME'] = 'restdb'
app.config['MONGO_URI'] = 'mongodb://localhost:27017/restdb'

mongo = PyMongo(app)

@app.route('/dessert', methods=['POST'])
def add_dessert():
  dessert = mongo.db.desserts
  name = request.json['name']
  calories = request.json['calories']
  dessert_id = dessert.insert({
    'name': name, 
    'calories': calories
})
  new_dessert = dessert.find_one({'_id': dessert_id })
  output = {
    'name' : new_dessert['name'], 
    'calories' : new_dessert['calories']
}
  return jsonify({'result' : output})

@app.route('/dessert', methods=['GET'])
def get_all_desserts():
  dessert = mongo.db.desserts
  output = []
  for s in dessert.find():
    s['_id'] = str(s['_id'])
    output.append({'_id' : s['_id'], 
                   'name' : s['name'], 
                   'calories' : s['calories']
    })
  return jsonify({'data' : output})

@app.route('/dessert/<dessert_id>', methods=['GET'])
def get_one_dessert(dessert_id):
  dessert = mongo.db.desserts
  s = dessert.find_one({"_id" : ObjectId(dessert_id)})
  s['_id'] = str(s['_id']) 
  if s:
    output = {'_id' : s['_id'], 'name' : s['name'], 'calories' : s['calories']}
  else:
    output = "No such name"
  return jsonify({'result' : output})

@app.route('/dessert/<dessert_id>', methods=['DELETE'])
def delete_one_dessert(dessert_id):
  dessert = mongo.db.desserts
  s = dessert.find_one({"_id" : ObjectId(dessert_id)})
  s['_id'] = str(s['_id'])
  dessert.remove({"_id" : ObjectId(dessert_id)}) 
  if s:
    output = {'_id' : s['_id'], 'name' : s['name'], 'calories' : s['calories']}
  else:
    output = "No such name"
  return jsonify({'result' : output})

if __name__ == '__main__':
    app.run(debug=True)
1
It'd probably be better to post the markup/source-code you used for your component rather than linking to codepen.io (the codepen itself is lacking external libraries to be of any use anyhow) - gabriel.hayes
Also, you posted you can access this.editedItem._id without a problem but also have to reload the webpage to access this.editedItem._id, is this correct or did you make a typo? - gabriel.hayes
Please post the actual code you're having a problem with... the codepen clearly cannot be used to reproduce your issue; you stated you are having problems accessing the information of the mongo database after you added an item, but the codepen shows no code for adding items.. The likely answer is that wherever you are adding an item, you need to refresh the data. - gabriel.hayes
@user1538301 I appreciate your coments. I posted the reproducible example. Let my know any doubts. - Ushuaia81
Isn't your post output missing the id? - artoju

1 Answers

2
votes

If I understood it correctly, you want to be able to see in the front-end the newly added item, including the generated ID, after posting it to backend, right?

So, you can just simply call the fetchItems() once you finish posting the new item. It will automaticly update the array of the shown items, including the newly added ID.

The ID property is created when the item is added to the database, so it's not possible to have it unless the back-end gives it back to the front-end.

axios.post('http://localhost:5000/dessert', {
    name: this.editedItem.name,
    calories: this.editedItem.calories
}).then(response => {
    this.fetchItems()
})

That means, once finishing the POST, fetchItems() again.