Reputation: 51
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
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
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
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
Reputation: 8538
Essentially, you have an incorrect attribute
in your Vue
instance.. You need to move firebase
into data
..
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
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