Tom Harpaz
Tom Harpaz

Reputation: 489

Rendering a new Vue component after click

I am using Vue-CLI. I have a Vue component which is called viewGenres.vue. This component contains Vuetify table which presents all of the current genres from Vue store. I am trying to add a new option for each genre which is "Edit".

My objective is that for each line in the table there will be an edit button. Once the button is clicked, a new component called editGenre.vue should be rendered.

This component should contain a filled-out form with all the existing details of the specific genre. I have several questions:

1) Once I click on the edit button, the following exception appears on browser:

ReferenceError: Vue is not defined at VueComponent.editGenre

2) In order for me to load the right properties from the DB, I need to define the "ID" prop of the editGenre component. Does anyone have any recommendation on the best method to do so?

This is viewGenres.vue: (the method editGenre is the one responsible for rendering the new component).

<template>
    <div class="root" ref="container">
        <h2>Genres Info</h2>
        <br>
        <v-data-table
            :headers="headers"
            :items="genres"
            hide-actions
            class="elevation-1">
            <template slot="items" slot-scope="props">
                <td class="text-xs-left">{{ props.item.id }}</td>
                <td class="text-xs-left">{{ props.item.name }}</td>
                <td class="text-xs-left">{{ props.item.desc }}</td>
                <td class="text-xs-left">{{ props.item.artists }}</td>
            <td class="text-xs-left"><v-btn flat @click="editGenre(props.item.id)">EDIT</v-btn></td>
                <td class="text-xs-left"><v-btn flat @click="deleteGenre(props.item.id)">Delete</v-btn></td>
            </template>
        </v-data-table> 
    </div>
</template>
<script>
import editGenre from '@/components/administratorView/Genres/editGenre.vue'
const firebase = require('../../../firebaseConfig.js')

export default {
    data: function(){
        return{
            headers: [
            { text: 'ID', value: 'id'},
            { text: 'Name', value: 'name'},
            { text: 'Description', value: 'desc'},
            { text: 'Artists', value: 'artists'},
      { text: 'Edit Genre'},
            { text: 'Delete From DB'}
            ]
        }
    },
    computed: {
    genres: function(){
      return this.$store.state.genre.genres
    }
    },
  components: {
    editGenre
  },
    methods: {
    editGenre: function(id){
      var ComponentClass = Vue.extend(editGenre)
      var instance = new ComponentClass()
      instance.$mount()
      this.$refs.container.appendChild(instance.$el)
    },
        deleteGenre: function(id){
            console.log("Trying to delete " +id)
            firebase.firestore.collection("genres").doc(id).delete().then(()=>{
            this.$store.dispatch('genre/getGenresFromDB')
                alert("Deleted Document Successfully")
            }).catch(function(error){
                alert(error)
            })
        }
    },
  mounted(){
    this.$store.dispatch('genre/getGenresFromDB')
  }
}
</script>
<style scoped>
</style>

This is editGenre.vue:

<template>
    <v-dialog v-model="editGenre" persistent max-width="500px">
        <v-card>
            <v-card-title>
                <h2>Edit Genre {{genre.name}}</h2>
            </v-card-title>
            <v-card-text>
                <v-text-field
                        v-model="name"
                        label="Name"
                        :error-messages="nameErrors"
                        @touch="$v.name.$touch()"
                        @blur="$v.name.$touch()"
                />
                <v-textarea
                        v-model="desc"
                        label="Description"
                        box
                />
                <v-combobox
                    v-model="artists"
                    label="Artists"
                    :items="artistNames"
                    :error-messages="artistsErrors"
                    @touch="$v.artists.$touch()"
                    @blur="$v.artists.$touch()"
                    multiple>
                </v-combobox>
                <v-btn
                        color="primary"
                        @click="submit">
                        Submit
                </v-btn>
                <v-btn
                    color="primary"
                    @click="close">
                    Close
                </v-btn>
            </v-card-text>          
        </v-card>   
    </v-dialog>
</template>
<script>
import { required } from 'vuelidate/lib/validators'
const firebase = require('../../../firebaseConfig')

export default{
    data: function(){
        return{
            name: '',
            desc: '',
            artists: []
        }
    },
    props: {
        id: String
    },
    mounted: function(){
        let docRef = firebase.firestore.collection("genres").doc(this.id)
        docRef.get().then(function(doc){
            if(doc.exists){
                this.name = doc.data().name
                this.desc = doc.data().desc
                this.artists = doc.data().artists
            }
            else{
                console.error("Doc Doesn't Exist!")
            }
        }).catch(function(error){
            console.error(error)
        })
    }
}
</script>
<style scoped>
</style>

Thank You! Tom

Upvotes: 0

Views: 2019

Answers (1)

Boussadjra Brahim
Boussadjra Brahim

Reputation: 1

You missed to import Vue in your viewGenres.vue component, so add it as follow :

   ....
   <script>
      import Vue from 'vue'
      import editGenre from '@/components/administratorView/Genres/editGenre.vue'
       const firebase = require('../../../firebaseConfig.js')
      ....

You could pass props by this way :

      var ComponentClass = Vue.extend(
              props:{
                id:{type:String, default () { return id}}
               },editGenre)

and remove this :

     props: {
       id: String
    }

according to Evan You :

It's not recommended to use new to manually construct child components. It is imperative and hard to maintain. You probably want to make your child components data-driven, using and v-for to dynamically render child components instead of constructing them yourself.

Upvotes: 2

Related Questions