iivri  andre
iivri andre

Reputation: 51

[Vue warn]: Property or method "names" is not defined on the instance but referenced during render

I'm setting up a Vue.js project and connecting it to Firebase for the real time database.

Problem: I am able to save the data to the Firebase database however I am not able to render it to the view.

Error Message:

[Vue warn]: Property or method "names" is not defined on the instance but referenced during render.

I have tried to adjust the vue instance "names" property by adding it the data function instead of making it a separate property in the instance, but that is not working.

<div id="app">

    <label for="">Name</label>
    <input type="text" name="" id="" v-model="name">
    <button @click="submitName()">Submit</button>


    <div>
        <ul>
            <li v-for="personName of names"
            v-bind:key="personName['.key']">
            {{personName.name}}
            </li>
        </ul>
    </div>

  </div>
<script>

import {namesRef} from './firebase'
export default {
  name: 'app',
  data () {
    return {
      name: "levi",
    }
  },
  firebase: {
    names: namesRef
  },
  methods: {
    submitName() {
      namesRef.push( {name:this.name, edit:false} )
    }

  }
}
</script>

<style>

Expected Result: Data saved to Firebase is rendered on the view

Actual result:

[Vue warn]: Property or method "names" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property.

Upvotes: 4

Views: 4930

Answers (5)

xaander1
xaander1

Reputation: 1160

Got mine working.

The solution is pretty simple.

Add names:[] to data object so it looks like:

...
  data () {
    return {
      name: "levi",
      names:[]
    }
  },
....

That's pretty much it.

Explaination

The firebase object data needs to be defined in order to use it

If you have more issues check the vuex documentation replicate that to your code.

Upvotes: 0

Naser Nourani
Naser Nourani

Reputation: 124

Try this

<script>

import {namesRef} from './firebase'
export default {
  name: 'app',
  data () {
    return {
      name: "levi",
    }
  },
  cumputed: {
    names: namesRef
  },
  methods: {
    submitName() {
      namesRef.push( {name:this.name, edit:false} )
    }

  }
}
</script>

Upvotes: 0

Steven Spungin
Steven Spungin

Reputation: 29149

Use a computed property for names. Computed is more appropriate than data in this case, mainly because the component does not own the data. If it eventually resided in a vuex store, for instance, it would then react to external changes.

<script>

import {namesRef} from './firebase'
export default {
  name: 'app',
  data () {
    return {
      name: "levi",
    }
  },
  computed: {
    names() {
      return namesRef
    }
  }
  methods: {
    submitName() {
      namesRef.push( {name:this.name, edit:false} )
    }

  }
}
</script>

Upvotes: 0

Matt Oestreich
Matt Oestreich

Reputation: 8538

Essentially, you have an incorrect attribute in your Vue instance.. You need to move firebase into data..

([CodePen])

I was unable to get this working in a Stack Snippet..

~~~THE FIX~~~


VUE/JS

firebase.initializeApp({
  databaseURL: "https://UR-DATABASE.firebaseio.com",
  projectId: "UR-DATABASE"
});

const database = firebase.database().ref("/users");

const vm = new Vue({
  el: "#app",
  data: {
    firebase: {
      names: []
    },
    name: "SomeName"
  },
  methods: {
    getFirebaseUsers() {
      this.firebase.names = [];
      database.once("value", users => {
        users.forEach(user => {
          this.firebase.names.push({
            name: user.child("name").val(),
            id: user.child("id").val()
          });
        });
      });
    },
    handleNameAdd() {
      let id = this.generateId();
      database.push({
        name: this.name,
        id: id
      });
      this.name = "";
      this.getFirebaseUsers();
    },
    generateId() {
      let dt = new Date().getTime();
      return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, c => {
        let r = ((dt + Math.random() * 16) % 16) | 0;
        dt = Math.floor(dt / 16);
        return (c == "x" ? r : (r & 0x3) | 0x8).toString(16);
      });
    }
  },
  mounted() {
    this.getFirebaseUsers();
  }
});

HTML

  <script src="https://www.gstatic.com/firebasejs/6.1.1/firebase.js"> . 
  </script>

  <div id="app">

    <label for="">Name</label>
    <input type="text" name="" id="" v-model="name">
    <button @click="handleNameAdd">Submit</button>


    <div>
        <ul>
            <li v-for="(person, index) in firebase.names"
            v-bind:key="person.id">
            {{person.name}} | {{person.id}}
            </li>
        </ul>
    </div>

  </div>



OLD ANSWER: This is what it should look like inside of data:

...
data() {
  firebase: {
    names: [],
  }
}
...

Therefore, the data in your v-for would be referenced via firebase.names like:

...
<li v-for="(personName, index) in firebase.names"
  :key="index">         // <<-- INDEX IS NOT THE BEST WAY TO STORE KEYS BUT ITS BETTER THAN NOTHING 
  //:key="personName.id // <<-- YOU COULD ALSO DO SOMETHING LIKE THAT, IF YOU HAVE A UNIQUE ID PER PERSON
  {{personName.name}}
</li>
...


OPTIMAL FIX:

You could use a computed property if you wanted to automatically save/retrieve data from firebase each time a user adds a new name...as outlined in the CodePen and Code Snippet..



THE ISSUE:

<script>
import {namesRef} from './firebase'
export default {
  name: 'app',
  data () {
    return {
      name: "levi",
    }
  },
  firebase: {        //  <<--- THIS IS INVALID, AND WHY IT'S NOT RENDERING
    names: namesRef  //        CHECK YOUR CONSOLE FOR ERRORS
  },
  methods: {
    submitName() {
      namesRef.push( {name:this.name, edit:false} )
    }

  }
}
</script>

Upvotes: 1

A.khalifa
A.khalifa

Reputation: 2496

Try this. You need to return the object in data

<script>

import {namesRef} from './firebase'
export default {
  name: 'app',
  data () {
    return {
      name: "levi",
      firebase: {
       names: namesRef
      },
    }
  },

  methods: {
    submitName() {
      namesRef.push( {name:this.name, edit:false} )
    }

  }
}
</script>

<style>

Upvotes: 0

Related Questions