Can't get Firebase data to display on simple Vue app - javascript

I'm trying to get a simple Vue+Firebase app running that allows you to send strings to the firebase database and have the messages be displayed using the "v-for" directive. However, I keep getting the error
Property or method "messages" is not defined on the instance but referenced during render
even though I'm pretty sure I'm using the correct syntax based on Vue's example on their site and the Vuefire github page to link up messages to the database. I can push to the database just fine, but for some reason I can't read the data from the database. I've been unable to get this to work for about a day and at this point any help is appreciated.
Here is my code for reference:
index.html:
<head>
<script src="https://www.gstatic.com/firebasejs/5.2.0/firebase.js"></script>
<script>
// Initialize Firebase
var config = { ... };
firebase.initializeApp(config);
</script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="message" placeholder="Type a message!">
<button v-on:click="sendData">Send Data</button>
<br>
<h3 v-for="msg in messages">{{msg.value}}</h3>
</div>
<script type="text/javascript" src="app.js"></script>
</body>
app.js:
var messageRef = firebase.database().ref('local/responses');
var app = new Vue({
el: '#app',
data: function () {
return {
message: ''
}
},
firebase: function () {
return {
messages: messageRef
}
},
methods: {
sendData: function () {
messageRef.push(this.message);
this.message = '';
}
}
});

You need to include the messages property in both the firestore return function as a database reference, as well as the data return function as an empty array for the database to bind to, as such.
var app = new Vue({
el: '#app',
data: function () {
return {
message: '',
messages: []
}
},
firebase: function () {
return {
messages: firebase.database().ref('local/responses')
}
},
methods: {
sendData: function () {
messageRef.push(this.message);
this.message = '';
}
}
});
This happens because you're trying to bind the Firestore reference to a piece of data that doesn't exist within your Vue instance, it needs that empty array for it to bind to the data property.

Related

Calling function shortly after page load, once results are received from controller

I'm trying to call a computed property (which relies on a data variable to be set from incoming json) upon page creation but it says that it can't read the data for 'undefined'. This is due to the data I need not being fully loaded, I'm pretty sure. When I set it to run 2 seconds after created(), it works just fine.
How can I neatly set this to only run the function on my data variable one time but ONLY once the data results are actually set?
<div id="app">
<div v-for="(value, employee) in employeeFunction" :key="employee">
#{{value}}
</div>
</div>
<script>
var vm =
new Vue({
el: "#app",
data: {
results: [
{//data is in here
}
],
},
created: function(){
this.interval = setInterval(() => this.employeeFunction(), 2000);
},
computed: {
employeeFunction() {
console.log('employee data')
employeeResults = this.results
console.log(employeeResults)
return employeeResults
},
}
});
</script>
Instead of using the created() lifecycle-hook try with mounted()

How to trigger Vue.js method from external JavaScript

I am trying to trigger a Vue.js method from a function that is in another JavaScript file. I have given the below code which I have tried.
sample.js
import vm from './vue.js';
function call( ) {
vm.$options.methods.displayData('I was called externally!')
}
call() // Here I am calling function
vue.js
var vm = new Vue({
el: '#app',
data: {
firstname : '' ,
lastname : ''
},
methods:{
displayData: function(s ) {
alert(s)
}
}
})
You don't need to access the $options object:
vm.displayData('I was called externally!')
This is simply using the instance to access its methods.
Edit for your comments below: To use the files without a bundler or es6 modules as you want, remove the import statement which is only for modules.
Here are the 3 complete files you would need for index.html, vue.js, sample.js:
index.html
<html>
<body>
<div id="app"></div>
<script src="https://unpkg.com/vue#2.6.12/dist/vue.js"></script>
<script src="vue.js"></script>
<script src="sample.js"></script>
</body>
</html>
vue.js
const vm = new Vue({
el: '#app',
data: () => ({
firstname : '',
lastname : ''
}),
methods:{
displayData: function(s) {
alert(s)
}
}
})
sample.js
function call( ) {
vm.displayData('I was called externally!')
}
call();

VUE.JS - How to use a class that is outside of vue.js in the javascript file of vue.js?

I'm using vue.js to create a webpage, and I'm trying to use a class (Authenticator) that is outside of my two files (Login.html and Login.js) that are using vue.js. But I can't seem to manage to import that class (Authenticator) in my Login.js file to use it's function...
Is there a way to do that? Here is my code:
Login.html
<!DOCTYPE html>
<html>
<head>
</head>
<body class="background">
<div class="border">
<div id="app">
[...]
</div> <!-- End of app -->
</div> <!-- End of border -->
<script src="./vue.js"></script>
<script src="./Login.js"></script>
<script src="../controller/Authenticator.js"></script>
</body>
</html>
Login.js
var app = new Vue({
el: '#app',
data: {
username: null,
password: null,
activeUsers: []
},
methods: {
verifyLogin: function () {
// Verify if fields have been filled
if (null === this.username || null === this.password) {
window.alert("Error, please fill out the form correctly!");
} else {
// If fields are filled, verify the authentication
var authenticator = new Authenticator(this.username);
var authenticated = authenticator.authenticateUser(this.username, this.password);
[...]
} else if (null === authenticated) {
// Error, if authentication failed
window.alert("Wrong password, please try again!")
}
}
}
}
});
Authenticator.js
const MongoClient = require('mongodb').MongoClient;
var url = "mongodb://192.168.99.100:27017/UserDB";
const bcrypt = require('bcrypt'); // Hash algorithm
const saltRounds = 10;
export default class Authenticator {
constructor(iNewUserName) {
this.mActiveUserNames.push(iNewUserName);
}
async authenticateUser(iUserName, iPassword) {
[...]
}
}
I get the error "Uncaught SyntaxError: Unexpected token 'export'" on the webpage console. Also, I tried to change the method of exporting by doing:
module.exports = Authenticator;
But then I get the error "Uncaught ReferenceError: require is not defined at Authenticator.js:2" from the webpage console.
Can someone help me please, I looked everywhere online, and I cannot find the solution?
Thank you.

Laravel and VueJS, access Vue instance.

I want to change a data property and run a method on my Vue instance within Laravel. However due to using webpack and laravel I can't seem to access the instance how I would expect to:
So window.app doesn't appear to be the correct instance of my Vue class.
Below is the Blade View i'm loading, as you can see I append a script tag to my main layout.blade.php, simply trying to change the Vue instance data property, and run a method.
#push('scripts')
<script>
app.unsaved = true;
app.triggerEvent(null, 'models', null);
</script>
#endpush
Below is part of my app.js (resources/assets/js/app.js):
const app = new Vue({
el: '#app',
components: {
'models-select': ModelsSelect
},
data: {
showModel: false,
unsaved: false
},
mounted: function() {
let _self = this;
(function() {
document.querySelectorAll("input, textarea, select").forEach(function(e) {
e.addEventListener('change', function() {
_self.unsaved = true;
e.classList.add('is-changed');
});
});
function unloadPage(){
if (_self.unsaved) return 'You appear to have un-saved changes!';
}
window.onbeforeunload = unloadPage;
})();
},
methods: {
triggerEvent: function(event, target, property)
{
app.$refs[target].update(event, property);
}
As you can see i'd expect to manipulate the Vue instance through the global app variable I have defined within the app.js. However this doesn't appear to be the case.
I get the following error when running the triggerEvent method:
app.triggerEvent is not a function
In your app.js file, change const app = new Vue({ to window.app = new Vue({.
Then within your <script> tags, change it to this.
<script>
window.app.unsaved = true;
window.app.triggerEvent(null, 'models', null);
</script>

Fire vue method from jquery on click event

I'm trying to append a click event to an already existing dom element.
<div class="logMe" data-log-id="{{ data.log }}"></div>
...
<div id="events"></div>
I can't seem to access outside vue methods within my jquery click handler. It will throw logData is not defined.
new Vue({
el: '#events',
mounted() {
$('.logMe').on('click', function() {
const data = $(this).data('log-id');
this.logData(data); // throws logData is not defined
});
},
methods: {
logData(id) {
console.log(id); // never fires
... hit server
},
},
});
If anyone knows of a better way to append click events to .html elements that would be great! But how can I bubble up and find my vue methods? Here's a fiddle to illustrate
To get your code working you would write it like this:
console.clear()
new Vue({
el: '#events',
mounted() {
$('.logMe').on('click', (evt) => {
console.log("called")
const data = $(evt.target).data('logId');
this.logData(data);
});
},
methods: {
logData(id) {
console.log(id);
},
},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://unpkg.com/vue#2.4.2"></script>
<div class="logMe" data-log-id="10">Something</div>
<div id="events"></div>
Note that the code uses an arrow function to define the click handler so that the appropriate this is captured to call the logData method on the Vue. However, doing that means you lose the this you want to get the data from the data property, so instead the example uses evt.target.
There is an alternative approach where you capture the Vue in a variable and call the method directly from your jQuery event.
console.clear()
const app = new Vue({
el: '#events',
methods: {
logData(id) {
console.log(id); // never fires
},
},
});
$('.logMe').on('click', function(){
app.logData($(this).data("logId"))
});
<script src="https://unpkg.com/vue#2.4.2"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div class="logMe" data-log-id="10">Something</div>
<div id="events"></div>
Much easier solution =
window.app = new Vue({
el: "#app",
methods: {
myMethod(data) { ... }
}
}
// jQuery
window.app.myMethod(data);

Categories

Resources